平台说明 - iOS

部署

使用macOS上的Qt Creator可以开发、构建、运行和调试适用于iOS的Qt应用程序。工具链由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开发库中信息属性列表文件的文档。

CMake中的Info.plist

CMake会为目标具有其MACOSX_BUNDLE属性设置为TRUE的目标生成一个默认的Info.plist文件。不幸的是,该文件不适合iOS项目。

相反,项目可以使用qt_add_executable,该命令将自动生成一个带有适用于iOS项目的默认值的Info.plist文件。

要指定一个自定义的Info.plist,项目可以将MACOSX_BUNDLE_INFO_PLIST目标属性设置为如下所示。这样做将禁用qt_add_executable提供的自动文件生成,并将使用CMake为项目提供的Info.plist文件的原生处理。

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完成的模板替换指定的目标属性和变量信息,请参阅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_DATA qmake 变量提供了一种指定要复制到应用程序包中的一组文件的方法。例如

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中的资源目录作为替代方案,可以使用以下方式用 qmake添加:

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 会从它生成所有必要的图标。也可以在资产目录中手动指定图像。

可以指定图标的详细列表在图标文件中查看。

文件名不重要,重要的是像素大小。为了支持通用 iOS 应用程序,需要以下图像

  • [email protected]: 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 文档进行。

当使用 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 6.4 开始,Qt 支持 CMake 的自定义启动屏幕,从 Qt 6.0 开始支持 qmake。

假设启动文件名为 Launch.storyboard,可以按以下方式添加到 Info.plist 中:

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

使用以下代码片段将启动屏幕复制到应用程序包中,使用 qmake:

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起就不再支持它们。请考虑改为使用启动屏幕。

启动图片需要复制到应用包中,并在Info.plist文件中使用UILaunchImages键设置其名称。

以下图片需要准备:

可以将这些图片添加到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.plist中使用UILaunchImageFile键指定单个启动图片,但自iOS 10.0起,对该功能的支持已被弃用。

原生图片选择器

如果您的Info.plist文件中包含NSPhotoLibraryUsageDescription条目,qmake将自动包含一个额外的插件,该插件可以启用对原生动图选择器的访问。如果您的QFileDialog目录设置为

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

或 alternately,在QML中的FileDialog目录设置为

shortcuts.pictures

那么将显示原生图片选择器,允许访问用户的相册。

表达支持的iOS版本

Apple平台有一个内置方式来表达应用程序支持的操作系统版本,它可以自动显示针对较老版本的友好的错误信息,提示用户更新OS,而不是崩溃和显示堆栈跟踪。

在表达对特定范围内的OS版本支持中所涉及的主要概念有:

  • 部署目标指定了您应用支持的最低的macOS或iOS版本。
  • SDK版本指定了您应用支持的最高的macOS或iOS版本。

当您为Apple平台开发应用程序时,您应始终使用最新版本的Xcode以及开发当时的最新SDK。在某些平台上,如iOS,如果不行,您实际上会被App Store拒绝。因此,SDK版本始终大于或等于部署目标。

当您为Apple平台开发应用程序时,您必须设置部署目标。Xcode工具链中的各种构建工具都有您可以使用来设置此值的标志,包括但不限于编译器和链接器。通过设置部署目标值,您明确表示您的应用程序至少必须在该版本上运行,且不会与OS的任何更早版本一起工作。然后,您需要确保您对系统API的使用与您所声明的相匹配。由于编译器知道您已声明的内容,它可以帮助确保这一点。

SDK版本被认为是一个与OS兼容的软最大版本。这意味着如果应用是用SDK构建的,即使是在更高版本的OS上,它也会继续使用该SDK的行为,因为操作系统会检查二进制的加载命令,并以向后兼容的方式模拟旧版OS。例如,如果应用是用macOS 10.12 SDK构建的,那么即便是在10.13及以上版本上,它也会继续使用10.12的行为。

然而,Mach-O二进制文件天生就是向前兼容的。例如,使用iOS 9 SDK构建的应用在iOS 10上运行良好,但在新版本中可能不会采用对某些功能所做的行为变更,除非该应用重新编译以针对更新后的SDK。

最低OS版本可以通过编译器和链接器标志表示,这些标志将其嵌入到Mach-O二进制文件中。此外,必须在应用的app bundle中设置LSMinimumSystemVersion键。此值必须与传递给编译器和链接器的值相同,因为在macOS上它将允许操作系统显示一个友好的错误对话框,表明该应用需要更高版本的操作系统,而不是崩溃对话框。《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文件,您必须将一个匹配部署目标的LSMinimumSystemVersion条目添加到Info.plist中,因为操作系统会将LSMinimumSystemVersion值作为权威值使用。

如果您指定的部署目标值低于Qt的要求,则在使用Qt不支持的老版本运行时,应用几乎肯定会在Qt库的某个位置崩溃。因此,请确保实际的构建系统代码反映了实际所需的最低OS版本。

向Apple App Store发布

如下所述,可以验证您的Qt iOS应用是否已准备好发布到App Store:详情请参阅提交应用。要提交应用,您可以使用Xcode或应用加载器(由Xcode安装)。Qt Creator不支持管理Xcode项目配置中所有设置的界面。

应用应在它目标支持的iOS版本和设备上进行测试。Qt应用的最低部署目标因Qt版本而异。更多信息,请参阅支持配置

实际的发布过程包括创建分发证书和配置文件,创建应用的签名存档,并在其上运行一系列验证测试。

有关更详细的信息,请参阅iOS开发者库中的应用发布指南

符号可见性警告

在链接 C++ 库的上下文中,函数和对象被称为符号。符号可以是 默认隐藏可见性

出于性能原因,Qt 以及许多其他库默认使用 隐藏 可见性进行源代码编译,并且只在它们打算在用户项目中使用时标记符号为 默认 可见性。

不幸的是,当某一库使用 隐藏 可见性进行编译,而用户项目应用或库使用 默认 可见性进行编译时,Apple 链接器可能会发出警告。

如果项目开发者想要消除该警告,他们需要将项目代码也编译为 隐藏 可见性。

在 CMake 中,可以通过将以下代码添加到您的 CMakeLists.txt 文件中来实现。

set(CMAKE_CXX_VISIBILITY_PRESET hidden)

在 qmake 中,可以通过将以下代码添加到您的 .pro 文件中来实现。

CONFIG+=hide_symbols

如果项目构建库,任何打算在另一个库或应用中使用库中的符号都需要显式标记为 默认 可见性。例如,可以通过对这样的函数或类使用 Q_DECL_EXPORT 进行注释来实现。

CMake 中的产品存档问题

由于 CMake 中的问题,尝试使用 iOS 应用创建产品存档可能会失败。

当尝试使用 Xcode 的产品 -> 存档菜单项创建存档,或者从命令行使用 xcodebuild -archivePath 时,都可能发生这种情况。

错误信息可能引用未定义的符号或不存在的文件路径。

为了解决这个问题,在尝试创建存档之前,请确保构建项目的 发布 版本。

© 2024 The Qt Company Ltd。本文件内包含的文档贡献的版权归其各自的拥有者。本文件内提供的文档是根据免费软件基金会发布的 GNU 自由文档许可证 1.3 版本 的条款许可的。Qt 及其相关标志是芬兰的 The Qt Company Ltd. 和/或世界上其他国家的商标。所有其他商标均为各自所有者的财产。