Platform Notes - iOS

Deployment

Developing, building, running, and debugging a Qt for iOS application can all be done with Qt Creator on macOS. The toolchain is provided by Apple's Xcode, and running qmake on a project targeted for iOS will also generate an Xcode project file (.xcodeproj), with initial application settings. As Qt Creator does not provide an interface for managing all of the settings specific to iOS platform, it is sometimes necessary to adjust them in Xcode directly. Checking that the application is configured correctly is especially important before submitting an application for publishing in Apple's App Store.

Information Property List Files

Information property list file (Info.plist) on iOS and macOS is used for configuring an application bundle. These configuration settings include:

  • Application display name and identifier
  • Required device capabilities
  • Supported user interface orientations
  • Icons and launch images

See the documentation on Information Property List File in iOS Developer Library for details.

When qmake is run, an Info.plist file is generated with appropriate default values.

It is advisable to replace the generated Info.plist with your own copy, to prevent it from being overwritten the next time qmake is run. You can define a custom information property list with QMAKE_INFO_PLIST variable in your .pro file.

ios {
    QMAKE_INFO_PLIST = ios/Info.plist
}

Application Assets

For files that cannot be bundled into Qt resources, QMAKE_BUNDLE_DATA qmake variable provides a way to specify a set of files to be copied into the application bundle. For example:

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

For image resources, an alternative way is to make use of asset catalogs in Xcode, which can be added in a similar way:

ios {
    QMAKE_ASSET_CATALOGS += ios/Assets.xcassets
}

Icons

Icons need to be set in the Info.plist and copied to the application bundle. Xcode has special support for icons, but when using Qt, it is usually better to set them in the .pro file.

To support all resolutions and devices, several images should be created. A detailed list of what is required is available at Icon files. The filename is not important, but the actual pixel size is. Just a few icons are required. However, to support both iPhone and iPad, the following images are required:

  • AppIcon29x29.png: 29 x 29
  • AppIcon29x29@2x.png: 58 x 58
  • AppIcon29x29@2x~ipad.png: 58 x 58
  • AppIcon29x29~ipad.png: 29 x 29
  • AppIcon40x40@2x.png: 80 x 80
  • AppIcon40x40@2x~ipad.png: 80 x 80
  • AppIcon40x40~ipad.png: 40 x 40
  • AppIcon50x50@2x~ipad.png: 100 x 100
  • AppIcon50x50~ipad.png: 50 x 50
  • AppIcon57x57.png: 57 x 57
  • AppIcon57x57@2x.png: 114 x 114
  • AppIcon60x60@2x.png: 120 x 120
  • AppIcon72x72@2x~ipad.png: 144 x 144
  • AppIcon72x72~ipad.png: 72 x 72
  • AppIcon76x76@2x~ipad.png: 152 x 152
  • AppIcon76x76~ipad.png: 76 x 76

These files should be copied to the application bundle by adding something like the following code snippet to the .pro file:

ios {
    ios_icon.files = $$files($$PWD/ios/AppIcon*.png)
    QMAKE_BUNDLE_DATA += ios_icon
}

For the icons to be used, the filenames also have to be listed in the Info.plist. The best way is to list all icon files using the CFBundleIconFiles key. The iPad specific version can be given using the CFBundleIcons~ipad key, by adding something like the following code snippet to Info.plist:

<key>CFBundleIcons</key>
<dict>
    <key>CFBundlePrimaryIcon</key>
    <dict>
        <key>CFBundleIconFiles</key>
        <array>
            <string>AppIcon29x29.png</string>
            <string>AppIcon29x29@2x.png</string>
            <string>AppIcon40x40@2x.png</string>
            <string>AppIcon57x57.png</string>
            <string>AppIcon57x57@2x.png</string>
            <string>AppIcon60x60@2x.png</string>
        </array>
    </dict>
</dict>
<key>CFBundleIcons~ipad</key>
<dict>
    <key>CFBundlePrimaryIcon</key>
    <dict>
        <key>CFBundleIconFiles</key>
        <array>
            <string>AppIcon29x29.png</string>
            <string>AppIcon29x29@2x.png</string>
            <string>AppIcon40x40@2x.png</string>
            <string>AppIcon57x57.png</string>
            <string>AppIcon57x57@2x.png</string>
            <string>AppIcon60x60@2x.png</string>
            <string>AppIcon29x29~ipad.png</string>
            <string>AppIcon29x29@2x~ipad.png</string>
            <string>AppIcon40x40~ipad.png</string>
            <string>AppIcon40x40@2x~ipad.png</string>
            <string>AppIcon50x50~ipad.png</string>
            <string>AppIcon50x50@2x~ipad.png</string>
            <string>AppIcon72x72~ipad.png</string>
            <string>AppIcon72x72@2x~ipad.png</string>
            <string>AppIcon76x76~ipad.png</string>
            <string>AppIcon76x76@2x~ipad.png</string>
        </array>
    </dict>
</dict>

This ensures that the appropriate files are copied to the right place and the correct icons are used as required by the Apple App Store. Ad-hoc distributions should also include the following filenames in the application bundle to visualize the application in iTunes:

  • iTunesArtwork 512x512
  • iTunesArtwork@2x 1024x1024

Launch Images

Like icons, launch images consist of images that need to be copied to the application bundle and keys that have to be set in the Info.plist.

To support the iPhone 6, a launch file (an interface builder .xib file or a storyboard file) should be provided. For more information, see Launch Images. Assuming that you called the launch file Launch.xib, it can be added to the Info.plist as follows:

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

It is possible to use launch images (PNG files), as described below, to support the iPhone 6, but it is not recommended. Qmake generates a default LaunchScreen.xib, so it is better to use another name for a custom launch screen to avoid clashes.

Starting with iOS 7, the launch images are defined using the UILaunchImages key. To support these devices, you need to prepare the following images:

  • 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

The images can be added to the Info.plist as follows:

<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>

To support earlier iOS versions, one can use the UILaunchImageFile string in the Info.plist:

<key>UILaunchImageFile</key>
<string>LaunchImage</string>

The name defaults to Default, but qmake generates some of the images, so it is easier to use another name (for example LaunchImage as we did) to avoid clashes.

  • LaunchImage.png: 320 x 480
  • LaunchImage@2x.png: 640 x 960
  • LaunchImage-568h@2x.png: 640 x 1136
  • LaunchImage-Landscape.png: 1024 x 748
  • LaunchImage-Landscape@2x.png: 2048 x 1496
  • LaunchImage-Portrait.png: 768 x 1004
  • LaunchImage-Portrait@2x.png: 1536 x 2008

You can change the filenames as long as the Info.plist and filenames stay in sync.

Finally, all these files have to be copied to the application bundle by adding something like the following code snippet to the .pro file:

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

This allows you to produce universal applications with valid LaunchImages as required by the Apple App Store.

Important: "launch_images" is used internally by Qt, so it will be overwritten if used in your .pro file.

Native Image Picker

If your Info.plist file contains an entry for NSPhotoLibraryUsageDescription, qmake will automatically include an extra plugin which enables access to the native image picker. If the directory in your QFileDialog is set to:

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

or alternatively the folder in a FileDialog in QML to:

shortcuts.pictures

then the native image picker is shown to allow access to the user's photo album.

Expressing Supported iOS Versions

Apple platforms have a built-in way to express the OS versions that an application supports, which allows older versions of the platforms to automatically display a user friendly error message prompting the user to update their OS, as opposed to crashing and displaying a stack trace.

The main concepts involved in expressing support for a particular range of OS versions are:

  • Deployment target specifies the hard minimum version of macOS, iOS, tvOS, or watchOS that your application supports.
  • SDK version specifies the soft maximum version of macOS, iOS, tvOS, or watchOS that your application supports.

When you develop an application for an Apple platform, you should always use the latest version of Xcode and the latest SDK available at the time of development. On some platforms, like iOS, you will actually be rejected from the App Store if you do not. Therefore, the SDK version is always greater than or equal to the deployment target.

When you develop an application for an Apple platform, you must set the deployment target. Various build tools within the Xcode toolchain all have a flag which you can use to set this value, including but not limited to the compiler and linker. By setting the deployment target value, you are explicitly declaring that your application must work on at least that version, and will not work with any earlier versions of the OS. It is then up to you to ensure that your use of the system APIs matches what you have declared. Since the compiler knows what you have declared, it can help in enforcing that.

The SDK version is considered a soft maximum version of the OS that an application is compatible with in the way that if the application is built with an SDK, it will continue to use the behaviors of that SDK even on newer OS versions, because the OS checks the binary's load commands and emulates backwards compatibility with the older OS. For example, if an application is built with the macOS 10.12 SDK, it will continue to use 10.12 behaviors even on 10.13 and above.

However, Mach-O binaries are inherently forward compatible. For example, an application built with the iOS 9 SDK will run just fine on iOS 10, but might not be opted into whatever behavior changes may have been made to certain functionality on the new release, until that application is recompiled against that newer SDK.

The minimum OS version can be expressed to the system by the compiler and linker flags that embed it into the Mach-O binary. In addition, the LSMinimumSystemVersion key must be set in the application's app bundle. This value must be equal to the value passed to the compiler and linker, because on macOS it will allow the OS to display a user friendly error dialog that says the application requires a newer version of the OS as opposed to a crash dialog. The LSMinimumSystemVersion is also the key that the App Store uses to display the required OS version; the compiler and linker flags have no power there.

For the most part, Qt applications will work without problems. For example, in qmake, the Qt mkspecs set QMAKE_IOS_DEPLOYMENT_TARGET, QMAKE_MACOSX_DEPLOYMENT_TARGET, QMAKE_TVOS_DEPLOYMENT_TARGET, or QMAKE_WATCHOS_DEPLOYMENT_TARGET to the minimum version that Qt itself supports. Similarly, in Qbs, the Qt modules set cpp.minimumIosVersion, cpp.minimumMacosVersion, cpp.minimumTvosVersion, or cpp.minimumWatchosVersion to the minimum version that Qt itself supports.

However, you must take care when you manually set your own target version. If you set it to a value higher than what Qt requires and supply your own Info.plist file, you must add an LSMinimumSystemVersion entry to the Info.plist that matches the value of the deployment target, because the OS will use the LSMinimumSystemVersion value as the authoritative one.

If you specify a deployment target value lower than what Qt requires, the application will almost certainly crash somewhere in the Qt libraries when run on an older version than Qt supports. Therefore, make sure that the actual build system code reflects the minimum OS version that is actually required.

Publishing to Apple App Store

Verifying that your Qt for iOS application is ready for publishing to App Store can be done as described in Submitting the Application. To submit the application, you can use Xcode, or the Application Loader (installed with Xcode). Qt Creator does not provide an interface for managing all of the settings in an Xcode project configuration.

The application should be tested on the iOS versions and devices that it is targeted to support. The minimum deployment target for Qt applications varies by Qt version. For more information, see Supported Platforms and Configurations.

The actual publishing process involves creating a distribution certificate and a provision profile, creating a signed archive of your application, and running a set of validation tests on it.

See the App Distribution Guide in iOS Developer Library for more information.