プラットフォームノート - iOS

デプロイメント

Qt for iOS アプリケーションの開発、ビルド、実行、デバッグは、すべて macOS 上の Qt Creator で行うことができます。ツールチェーンは Apple の Xcode によって提供され、iOS をターゲットとしたプロジェクトで qmake または CMake を実行すると、アプリケーションの初期設定を含む Xcode プロジェクトファイル (.xcodeproj) も生成されます。Qt Creator には iOS プラットフォーム固有の設定を管理するためのインターフェイスが用意されていないため、Xcode で直接設定する必要があります。アプリケーションが正しく設定されているかどうかを確認することは、Apple の App Store で公開するためにアプリケーションを提出する前に特に重要です。

アプリケーションバンドル

iOS アプリケーションは、通常、自己完結型のアプリケーションバンドルとしてデプロイされます。アプリケーションバンドルには、アプリケーションの実行ファイルと、Qt ライブラリ、プラグイン、翻訳、その他アプリケーションが必要とするリソースなどの依存関係が含まれています。

CMake でアプリケーションバンドルとしてアプリケーションをビルドするには、実行可能ターゲットに MACOSX_BUNDLEプロパティを設定します:

qt_add_executable(app)
if(APPLE)
    set_target_properties(tst_manual_ios_assets PROPERTIES MACOSX_BUNDLE TRUE)
endif()

qmakeでは、バンドルがデフォルトです。これを無効にするには、プロジェクトファイル (.pro) でCONFIG -= app_bundle を設定します。

情報プロパティリストファイル

iOSとmacOSの情報プロパティリストファイル(Info.plist)は、アプリケーションバンドルの設定に使用されます。これらの設定には以下が含まれます:

  • アプリケーションの表示名と識別子
  • 必要なデバイス機能
  • サポートされるユーザーインターフェースの方向
  • アイコンと起動イメージ

詳細については、iOS Developer LibraryのInformation Property List Fileのドキュメントを参照してください。

CMakeを使ったInfo.plist

ターゲットがMACOSX_BUNDLE プロパティをTRUE に設定している場合、CMake はデフォルトのInfo.plist ファイルを生成します。残念ながら、このファイルは iOS プロジェクトには適していません。

代わりに、プロジェクトはqt_add_executableを使うことができ、iOSプロジェクトに適したデフォルト値のInfo.plist ファイルを自動的に生成します。

カスタムのInfo.plist を指定するには、MACOSX_BUNDLE_INFO_PLIST target プロパティを設定します。そうすることで、qt_add_executableが提供するファイルの自動生成が無効になり、代わりに、プロジェクトが提供するInfo.plist ファイルの CMake のネイティブ処理が使用されます。

qt_add_executable(app)
if(IOS)
    set_target_properties(app
        PROPERTIES MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/ios/Info.plist")
endif()

CMake によって実行されるテンプレート置換で指定できるターゲットプロパティや変数については、CMake MACOSX_BUNDLE_INFO_PLIST ドキュメントを参照してください。

QMake による Info.plist

qmake を実行すると、Info.plist ファイルが適切なデフォルト値で生成されます。

生成されたInfo.plistは、次にqmakeを実行したときに上書きされないように、自分のコピーと置き換えることをお勧めします。.proファイルのQMAKE_INFO_PLIST変数でカスタム情報プロパティリストを定義することができます。

ios {
    QMAKE_INFO_PLIST = ios/Info.plist
}

アプリケーションアセット

Qt リソースにバンドルできないファイルについては、QMAKE_BUNDLE_DATAqmake 変数でアプリケーションバンドルにコピーするファイルのセットを指定できます。例えば

ios {
    fontFiles.files = $$files(fonts/*.ttf)
    fontFiles.path = fonts
    QMAKE_BUNDLE_DATA += fontFiles
}

CMakeの場合、同じことを次のように行うことができます:

qt_add_executable(app)
file(GLOB_RECURSE font_files CONFIGURE_DEPENDS "fonts/*.ttf")
if(IOS AND font_files)
    target_sources(app PRIVATE ${font_files})
    set_source_files_properties(
        ${font_files}
        PROPERTIES MACOSX_PACKAGE_LOCATION Resources/fonts)
endif()

画像リソースについては、Xcodeのアセットカタログを利用する方法もあります:

ios {
    QMAKE_ASSET_CATALOGS += ios/Assets.xcassets
}

CMakeで:

qt_add_executable(app)
set(asset_catalog_path "ios/Assets.xcassets")
target_sources(app PRIVATE "${asset_catalog_path}")
set_source_files_properties(
    ${asset_catalog_path}
    PROPERTIES MACOSX_PACKAGE_LOCATION Resources)

アイコン

Xcode 13 から、アイコンは、通常AppIcon と呼ばれるアセットカタログのアイコンセットに追加する必要があります。Xcode は、正しいキーと値でInfo.plist ファイルを更新し、アプリケーションバンドルに必要なアイコンファイルを直接コピーします。

Xcode 14 からは、1024x1024 ピクセルの大きさの画像が必要です。Xcode は、そこからすべての必要なアイコンを生成します。アセットカタログで画像を手動で指定することも可能です。

指定できるアイコンの詳細なリストは、Icon files で入手できます。

ファイル名は重要ではありませんが、実際のピクセルサイズは重要です。ユニバーサルiOSアプリケーションをサポートするには、以下の画像が必要です:

  • AppIcon60x60@2x.png:120 x 120 (iPhone用)
  • AppIcon76x76@2x~ipad.png:152 x 152(iPad用)
  • AppIcon167x167.png:167x167(iPad Pro用)
  • AppIcon1024x1024.png:1024 x 1024(App Store用)

アドホック配布では、iTunesでアプリケーションを視覚化するために、アプリケーションバンドルに以下のファイル名を含める必要があります:

  • iTunesArtwork 512x512
  • iTunesArtwork@2x 1024x1024

アイコンを追加する最も簡単な方法は、XcodeのCreate asset catalogs and setsのドキュメントに従うことです。

CMakeでプロジェクトをビルドする際、アプリのアイコンがXcodeによって生成されるように、以下のXcode属性も指定する必要があります。

set_target_properties(app_target_name PROPERTIES
    XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME AppIcon)

以下は、Xcode 14用のAssets.xcassets/AppIcon.appiconset/Contents.json ファイルがどのように見えるかの例です:

{
  "images" : [
    {
      "idiom" : "universal",
      "platform" : "ios",
      "scale" : "2x",
      "size" : "20x20"
    },
    {
      "idiom" : "universal",
      "platform" : "ios",
      "scale" : "3x",
      "size" : "20x20"
    },
    {
      "idiom" : "universal",
      "platform" : "ios",
      "scale" : "2x",
      "size" : "29x29"
    },
    {
      "idiom" : "universal",
      "platform" : "ios",
      "scale" : "3x",
      "size" : "29x29"
    },
    {
      "idiom" : "universal",
      "platform" : "ios",
      "scale" : "2x",
      "size" : "38x38"
    },
    {
      "idiom" : "universal",
      "platform" : "ios",
      "scale" : "3x",
      "size" : "38x38"
    },
    {
      "idiom" : "universal",
      "platform" : "ios",
      "scale" : "2x",
      "size" : "40x40"
    },
    {
      "idiom" : "universal",
      "platform" : "ios",
      "scale" : "3x",
      "size" : "40x40"
    },
    {
      "idiom" : "universal",
      "platform" : "ios",
      "scale" : "2x",
      "size" : "60x60"
    },
    {
      "idiom" : "universal",
      "platform" : "ios",
      "scale" : "3x",
      "size" : "60x60"
    },
    {
      "idiom" : "universal",
      "platform" : "ios",
      "scale" : "2x",
      "size" : "64x64"
    },
    {
      "idiom" : "universal",
      "platform" : "ios",
      "scale" : "3x",
      "size" : "64x64"
    },
    {
      "idiom" : "universal",
      "platform" : "ios",
      "scale" : "2x",
      "size" : "68x68"
    },
    {
      "idiom" : "universal",
      "platform" : "ios",
      "scale" : "2x",
      "size" : "76x76"
    },
    {
      "idiom" : "universal",
      "platform" : "ios",
      "scale" : "2x",
      "size" : "83.5x83.5"
    },
    {
      "filename" : "AppIcon1024x1024.png",
      "idiom" : "universal",
      "platform" : "ios",
      "size" : "1024x1024"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}

起動画面と起動イメージ

起動画面

すべてのiOSアプリは、アプリの起動時に表示される起動画面を提供する必要があります。起動画面はインターフェイスビルダ(.xib )ファイルで、ストーリーボードファイルとも呼ばれます。詳細については、アプリの起動画面を指定するを参照してください。

起動画面のサポートはiOS 9.0で導入されました。

qmakeもCMakeも、LaunchScreen.storyboard というデフォルトの起動画面を生成します。

カスタム起動画面を指定するには、それをアプリケーション・バンドルにコピーし、UILaunchStoryboardName キーをInfo.plist ファイル内の起動画面の名前に設定する必要があります。

QtはQt 6.4からCMakeで、Qt 6.0からqmakeでカスタム起動画面をサポートしています。

起動ファイルをLaunch.storyboard と呼ぶと仮定すると、Info.plist に次のように追加できます:

<key>UILaunchStoryboardName</key>
<string>Launch</string>

qmakeで起動画面をアプリケーションバンドルにコピーするには、プロジェクトの.proファイルで次のコードスニペットを使用します:

ios {
    QMAKE_IOS_LAUNCH_SCREEN = $$PWD/Launch.storyboard
}

CMakeを使用します:

qt_add_executable(app)
if(IOS)
    set_target_properties(app PROPERTIES
        QT_IOS_LAUNCH_SCREEN "${CMAKE_CURRENT_SOURCE_DIR}/Launch.storyboard")
endif()

起動イメージ

起動画面の代わりに起動画像(PNGファイル)を指定することも可能です。

注意: iOS 13.0以降、起動画像のサポートは非推奨となっています。代わりに起動画面に切り替えることを検討してください。

起動イメージはアプリケーションバンドルにコピーし、UILaunchImages キーでInfo.plist ファイルに名前を設定する必要があります。

以下の画像を用意する必要があります:

  • LaunchImage-iOS7-568h@2x.png:640 x 1136
  • LaunchImage-iOS7-Landscape.png:1024 x 768
  • LaunchImage-iOS7-Landscape@2x.png:2048 x 1536
  • LaunchImage-iOS7-Portrait.png:768 x 1024
  • LaunchImage-iOS7-Portrait@2x.png:1536 x 2048
  • LaunchImage-iOS7@2x.png:640 x 960

画像は以下のようにInfo.plist

<key>UILaunchImages</key>
<array>
    <dict>
        <key>UILaunchImageMinimumOSVersion</key>
        <string>7.0</string>
        <key>UILaunchImageName</key>
        <string>LaunchImage-iOS7</string>
        <key>UILaunchImageOrientation</key>
        <string>Portrait</string>
        <key>UILaunchImageSize</key>
        <string>{320, 568}</string>
    </dict>
    <dict>
        <key>UILaunchImageMinimumOSVersion</key>
        <string>7.0</string>
        <key>UILaunchImageName</key>
        <string>LaunchImage-iOS7</string>
        <key>UILaunchImageOrientation</key>
        <string>Portrait</string>
        <key>UILaunchImageSize</key>
        <string>{320, 480}</string>
    </dict>
</array>
<key>UILaunchImages~ipad</key>
<array>
    <dict>
        <key>UILaunchImageMinimumOSVersion</key>
        <string>7.0</string>
        <key>UILaunchImageName</key>
        <string>LaunchImage-iOS7-Landscape</string>
        <key>UILaunchImageOrientation</key>
        <string>Landscape</string>
        <key>UILaunchImageSize</key>
        <string>{768, 1024}</string>
    </dict>
    <dict>
        <key>UILaunchImageMinimumOSVersion</key>
        <string>7.0</string>
        <key>UILaunchImageName</key>
        <string>LaunchImage-iOS7-Portrait</string>
        <key>UILaunchImageOrientation</key>
        <string>Portrait</string>
        <key>UILaunchImageSize</key>
        <string>{768, 1024}</string>
    </dict>
    <dict>
        <key>UILaunchImageMinimumOSVersion</key>
        <string>7.0</string>
        <key>UILaunchImageName</key>
        <string>LaunchImage-iOS7</string>
        <key>UILaunchImageOrientation</key>
        <string>Portrait</string>
        <key>UILaunchImageSize</key>
        <string>{320, 568}</string>
    </dict>
    <dict>
        <key>UILaunchImageMinimumOSVersion</key>
        <string>7.0</string>
        <key>UILaunchImageName</key>
        <string>LaunchImage-iOS7</string>
        <key>UILaunchImageOrientation</key>
        <string>Portrait</string>
        <key>UILaunchImageSize</key>
        <string>{320, 480}</string>
    </dict>
</array>

qmakeを使用してアプリケーションバンドルに打ち上げイメージをコピーするには、プロジェクトの.proファイルに次のコードスニペットを使用します:

ios {
    app_launch_images.files = $$files($$PWD/ios/LaunchImage*.png)
    QMAKE_BUNDLE_DATA += app_launch_images
}

CMakeを使用します:

qt_add_executable(app)
file(GLOB_RECURSE launch_images CONFIGURE_DEPENDS "ios/LaunchImage*.png")
if(IOS AND launch_images)
    target_sources(app PRIVATE ${launch_images})
    set_source_files_properties(
        ${launch_images}
        PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
endif()

注: 以前のiOSバージョンでは、Info.plistUILaunchImageFile キーを使って単一の起動イメージを指定することができましたが、iOS 10.0以降、このサポートは廃止されました。

ネイティブ画像ピッカー

Info.plist ファイルにNSPhotoLibraryUsageDescription のエントリが含まれている場合、qmake はネイティブイメージピッカーへのアクセスを可能にする追加プラグインを自動的に含めます。QFileDialog のディレクトリが

QStandardPaths::standardLocations(QStandardPaths::PicturesLocation).last();

または、QMLのFileDialog のフォルダを次のように設定してください:

shortcuts.pictures

に変更すると、ネイティブのイメージピッカーが表示され、ユーザーのフォトアルバムにアクセスできるようになります。

サポートされるiOSバージョンの表現

アップルのプラットフォームには、アプリケーションがサポートするOSバージョンを表現する方法が組み込まれています。これにより、古いバージョンのプラットフォームでは、クラッシュしてスタックトレースを表示するのではなく、OSをアップデートするよう促すユーザーフレンドリーなエラーメッセージを自動的に表示することができます。

特定の範囲のOSバージョンをサポートすることを表現するための主な概念は以下の通りです:

  • デプロイメントターゲットは、アプリケーションがサポートするmacOSまたはiOSのハード的な最小バージョンを指定します。
  • SDKバージョンは、アプリケーションがサポートするmacOSまたはiOSのソフトな最大バージョンを指定します。

Apple プラットフォーム用のアプリケーションを開発する場合、常に開発時に利用可能な Xcode の最新バージョンと最新の SDK を使用する必要があります。iOSのようないくつかのプラットフォームでは、そうしないと実際にApp Storeからリジェクトされます。したがって、SDK のバージョンは常にデプロイメントターゲット以上です。

Apple プラットフォーム用のアプリケーションを開発する場合、デプロイメントターゲットを設定する必要があります。Xcode ツールチェーン内の様々なビルドツールは、コンパイラとリンカを含むがこれに限定されない、この値を設定するために使用できるフラグを持っています。デプロイメントターゲットの値を設定することで、あなたのアプリケーションは少なくともそのバージョンで動作しなければならず、それ以前のバージョンのOSでは動作しないことを明示的に宣言することになります。そして、システムAPIの使用が宣言したものと一致しているかどうかは、あなた次第です。コンパイラーは、あなたが宣言した内容を知っているので、それを強制する手助けをすることができます。

SDKバージョンは、アプリケーションがあるSDKでビルドされた場合、OSがバイナリのロードコマンドをチェックし、古いOSとの後方互換性をエミュレートするため、新しいOSバージョンでもそのSDKの動作を使用し続けるという意味で、アプリケーションが互換性を持つOSのソフトな最大バージョンとみなされます。例えば、アプリケーションがmacOS 10.12 SDKでビルドされている場合、10.13以上でも10.12のビヘイビアを使い続けます。

しかし、Mach-Oバイナリは本質的に前方互換性があります。例えば、iOS 9 SDKでビルドされたアプリケーションはiOS 10でも問題なく動作しますが、新しいSDKに対して再コンパイルされるまでは、新しいリリースで特定の機能が変更されたとしても、その動作にオプトインされない可能性があります。

最小OSバージョンは、Mach-Oバイナリに組み込むコンパイラとリンカのフラグによってシステムに表現される。さらに、LSMinimumSystemVersion キーがアプリケーションのバンドルに設定されていなければなりません。この値は、コンパイラとリンカに渡される値と等しくなければなりません。なぜなら、macOSでは、クラッシュ・ダイアログではなく、アプリケーションがOSの新しいバージョンを必要とするというユーザーフレンドリーなエラー・ダイアログをOSに表示させることができるからです。また、LSMinimumSystemVersion は、App Storeが必要なOSバージョンを表示するために使用するキーでもあります。コンパイラとリンカのフラグには何の力もありません。

ほとんどの場合、Qtアプリケーションは問題なく動作します。例えば qmake では、Qt mkspecs でQMAKE_IOS_DEPLOYMENT_TARGETQMAKE_MACOSX_DEPLOYMENT_TARGETを Qt 自身がサポートする最小バージョンに設定します。同様に、Qbsでは、Qtモジュールはcpp.minimumIosVersioncpp.minimumMacosVersioncpp.minimumTvosVersioncpp.minimumWatchosVersion をQt自身がサポートする最小バージョンに設定します。

ただし、ターゲット・バージョンを手動で設定する場合は注意が必要です。Qtが要求する値よりも高い値に設定し、独自のInfo.plist ファイルを提供する場合、デプロイメントターゲットの値と一致するInfo.plist に、LSMinimumSystemVersion エントリを追加する必要があります。なぜなら、OSはLSMinimumSystemVersion の値を権威あるものとして使用するからです。

Qt が要求する値よりも低いデプロイメント ターゲットの値を指定した場合、Qt がサポートするバージョンよりも古いバージョンで実行すると、Qt ライブラリのどこかでアプリケーションがクラッシュします。そのため、実際のビルドシステムのコードには、実際に必要とされる最小の OS バージョンが反映されていることを確認してください。

Apple App Store への公開

Qt for iOS アプリケーションが App Store に公開できる状態であることの確認は、「アプリケーションの提出」で説明する方法で行うことができます。アプリケーションを提出するには、Xcode または Application Loader (Xcode と一緒にインストールされます) を使用します。Qt Creator は、Xcode プロジェクト設定のすべての設定を管理するためのインターフェイスを提供しません。

アプリケーションは、サポート対象となる iOS のバージョンとデバイスでテストする必要があります。Qt アプリケーションの最小デプロイメントターゲットは、Qt バージョンによって異なります。詳細については、サポートされている設定を参照してください。

実際の公開プロセスでは、配布証明書とプロビジョンプロファイルを作成し、アプリケーションの署名付きアーカイブを作成し、一連の検証テストを実行します。

詳細は iOS Developer Library のApp Distribution Guideを参照してください。

シンボルの可視性に関する警告

C++ライブラリのリンクでは、関数とオブジェクトはシンボルと呼ばれます。シンボルには、default またはhidden可視性があります。

パフォーマンス上の理由から、Qtや他の多くのライブラリは、デフォルトでhidden の可視性を使用してソースをコンパイルし、ユーザープロジェクトで使用する場合にのみ、シンボルにdefault の可視性をマークします。

残念ながら、あるライブラリがhidden でコンパイルされ、ユーザープロジェクトのアプリケーションやライブラリがdefault でコンパイルされると、Apple のリンカーは警告を出すことがあります。

プロジェクト開発者が警告を消したい場合は、プロジェクト・コードもhidden でコンパイルする必要があります。

CMakeでは、以下のコードをCMakeLists.txt に追加することで、これを行うことができます:

set(CMAKE_CXX_VISIBILITY_PRESET hidden)

qmakeでは、.pro ファイルに以下のコードを追加することで可能です:

CONFIG+=hide_symbols

プロジェクトがライブラリをビルドする場合、ライブラリのシンボルが他のライブラリやアプリケーションで使用されることを意図している場合は、default visibilityを明示的にマークする必要があります。例えば、そのような関数やクラスには、Q_DECL_EXPORT のアノテーションを付けてください。

CMakeでの製品アーカイブの問題

CMake の問題により、iOS アプリケーションでプロダクトアーカイブを作成しようとすると失敗することがあります。

これは、Xcode で Product -> Archive メニュー項目を使用してアーカイブを作成しようとしたとき、またはコマンドラインからxcodebuild -archivePath を使用してアーカイブを作成しようとしたときの両方で発生する可能性があります。

エラーメッセージは、未定義のシンボルや存在しないファイルパスを参照している可能性があります。

この問題を回避するには、アーカイブを作成する前に、プロジェクトのRelease バージョンをビルドしてください。

CMake Xcode プロジェクトで作成された xcarchive に dSYM バンドルがありません。

Xcode のバグと特定のCMake の制限のため、CMake で生成された Xcode プロジェクトは、Xcode のアーカイブタスク中に、アプリケーションのdSYM バンドルをxcarchive に含めることに失敗します。

Qt は、dSYM バンドルがxcarchive に含まれるように、オプトインとして回避策を提供しますが、それにはトレードオフが伴います。つまり、以下のCMake機能は正しく動作しません:

  • $<TARGET_FILE:app> ジェネレータ式が、アプリのバイナリにつながらない無効なパスに展開される可能性があります。
  • CMAKE_RUNTIME_OUTPUT_DIRECTORY 変数とそれに関連するRUNTIME_OUTPUT_DIRECTORY ターゲットプロパティは、設定されていても無視されます。
  • その他の未知の問題

上記の問題を軽減するには、以下の方法があります:

  • プロジェクトの開発中ではなく、xcarchive を作成する場合にのみ回避策を有効にする。
  • プロジェクトのルート・ディレクトリにのみ実行可能ファイルとライブラリを追加し、add_subdirectory の呼び出しには追加しない。

回避策を有効にするには、以下のオプションを使用してプロジェクトを構成します:

cmake . -DQT_USE_RISKY_DSYM_ARCHIVING_WORKAROUND=ON

または、qt_add_executable またはqt_add_library 呼び出しの前にプロジェクトで変数を設定します:

set(QT_USE_RISKY_DSYM_ARCHIVING_WORKAROUND ON)

...

qt_add_executable(app)

本書に含まれる文書の著作権は、それぞれの所有者に帰属します。 本書で提供されるドキュメントは、Free Software Foundation が発行したGNU Free Documentation License version 1.3に基づいてライセンスされています。 Qtおよびそれぞれのロゴは、フィンランドおよびその他の国におけるThe Qt Company Ltd.の 商標です。その他すべての商標は、それぞれの所有者に帰属します。