iOS 与 Xcode 服务器的持续集成解释
已发表: 2022-03-11介绍
在 Xcode 9 之前,使用 Apple 持续集成工具是一个繁琐而复杂的过程,需要购买和安装额外的 macOS 服务器应用程序。 这导致许多开发人员放弃了为他们的 iOS 项目进行持续集成的想法,或者求助于第三方解决方案,取得了不同程度的成功。
不过,在 2017 年 9 月 Xcode 9.0 发布后,流程大大简化,包括自动代码签名的选项,现在完全集成到 Xcode 中。 因此,它不需要任何额外的应用程序或工具。
虽然 Fastlane、Bluepill 等第三方解决方案有很大的帮助,并且可以为您完成大量繁重的工作,但本文将探讨单独使用 Xcode 和 Apple 工具来满足您的持续集成需求的功能。 我们还将使用手动代码签名,因为这对很多人来说似乎是个问题,而且当涉及到多个构建配置时,自动签名也往往不是最佳解决方案。
注意:本文基于 Xcode 9.4.1 并侧重于 iOS 应用程序开发,但其中很多内容适用于 Xcode 10(目前作为 beta 5 构建)和 macOS 应用程序开发。
设置 Xcode 服务器
除了简化实际的集成过程之外,Xcode 9 还简化了 Xcode Server 设置过程。
在已指定为 CI 服务器的 macOS 机器上启动 Xcode 应用程序并打开 Preferences。
导航到最后一个选项卡,名为Server & Bots 。
通过单击右上角的开关打开 Xcode Server 功能。 然后,您将被要求选择一个用户来在这台机器上运行和执行构建脚本。 为此目的拥有一个专门的用户可能是个好主意,而不是使用预先存在的用户。
请注意,此用户必须登录到系统才能运行任何 Xcode 机器人。 登录后,您应该会在用户名旁边看到一个绿色圆圈。
而已! 让我们仔细看看 Xcode 机器人。
如何配置 Xcode 机器人
现在您已准备好开始配置 Xcode 机器人以在此服务器上运行。 这可以在与服务器连接到同一网络的任何开发机器上完成。
在您的开发机器上打开 Xcode,然后从顶部菜单中单击Xcode > Preferences 。 然后,转到“帐户”选项卡并单击左下角的+图标。 从出现的对话框中选择 Xcode Server。
要创建机器人,只需在 Xcode 中打开您的项目,然后从顶部菜单中选择Product > Create Bot…选项。 机器人设置有许多步骤,我们将在接下来的部分中探讨它们。
自动化应用程序分发
iOS 应用程序构建自动化最常见的应用之一是配置机器人以将应用程序上传到 iOS 分发平台,例如 TestFlight、Fabric 等。
正如我之前解释的,本文将只探讨上传到 App Store Connect 和直接从 Xcode 服务器下载,因为这些是 Apple 用于 iOS 应用程序分发的原生工具。
使用 Xcode 的 App Store Connect 分发
在配置机器人之前,请确保您拥有与您的应用开发项目的捆绑 ID 匹配的 App Store Connect 应用记录。 还值得注意的是,每个构建都需要有一个由构建版本和构建号组成的唯一标识符。 当我们稍后讨论 Xcode 机器人设置时,我们将探讨如何确保满足这些条件。
第 1 步:设置正确的构建配置是获得所需内容的关键步骤。 确保选择生成要上传到 App Store Connect 的应用程序的方案和配置。 这包括确保构建配置使用在您团队的 Apple Developer 门户(用于代码签名)以及 App Store Connect 门户(用于自动上传应用程序)中注册的适当捆绑包 ID .
第 2 步:虽然仍在“配置”选项卡上,但我们需要指定导出选项。 我们将探索导出选项属性列表,因此请确保选中“使用自定义导出选项列表”。
第 3 步:现在是我们制作导出选项属性列表的时候了。 如果您输入xcodebuild --help
,则可以在此文件中使用完整的密钥列表,但我们将在此处探索此机器人配置中使用的密钥:
-
compileBitcode
– Bitcode 是 Apple 用于应用程序源代码的临时输出格式。 换句话说,它是您的源代码在编译为特定架构的机器代码之前转换的格式。 它的目标是拥有一个单一的代码容器,如果在指令集中进行优化,则可以进一步优化,并且还能够将其编译为相同格式的未来架构。 但是,这对您的应用程序没有任何影响。 由您决定是否要启用它。 -
method
– 此参数指定您要导出的产品类型。 苹果通过指定的受众来区分产品——开发只允许你将它安装在配置文件中指定的设备上,企业允许每个人都安装它,但他们需要在运行应用程序之前明确信任这个开发配置文件,而应用商店是将其分发到 App Store 或 App Store Connect,因此我们将使用此值。 -
provisioningProfiles
– 这是不言自明的。 但这里有两点需要注意:导出选项属性列表中的配置文件是一个字典,其中键对应于产品的捆绑 ID,值对应于用于对其进行代码签名的配置文件的名称。 -
signingCertificate
——另一个不言自明的论点。 此字段的值可以是完整的证书名称或 SHA-1 哈希。 -
teamID
– 另一个不言自明的论点。 这是在您注册 Apple Developer 计划时 Apple 向您的组织颁发的 10 个字符长的标识符。 -
uploadBitcode
– 是否上传 bitcode(如果您选择编译成它),以便它可以在 AppStore Connect 中用于生成新的优化构建或用于未来架构的构建。 -
uploadSymbols
– 上传您的调试符号,以便您可以获得有意义的崩溃报告,而不仅仅是内存转储和程序集堆栈。
所以现在,您的导出选项属性列表可能如下所示:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>compileBitcode</key> <false/> <key>method</key> <string>app-store</string> <key>provisioningProfiles</key> <dict> <key>com.bundle.id</key> <string>ProvisioningProfileName</string> </dict> <key>signingCertificate</key> <string>Signing Certificate Exact Name or SHA-1 hash value</string> <key>teamID</key> <string>??????????</string> <key>uploadBitcode</key> <false/> <key>uploadSymbols</key> <true/> </dict> </plist>
第 4 步:选择您创建的 .plist 作为导出选项属性列表。
第 5 步:接下来是“计划”选项卡——根据您的喜好进行设置。
第 6 步:在“签名”选项卡上,确保取消选中“允许 Xcode 服务器管理我的证书和配置文件”选项,并在“证书和配置文件”页面上自行上传匹配的签名证书和配置文件。
第 7 步:设备选项卡应保持原样,因为我们正在上传应用程序而不是对其进行测试。
第 8 步: Arguments选项卡允许您显式设置 xcodebuild 参数或环境变量,这些参数或环境变量可用于您的构建或集成前和集成后脚本。
第 9 步:最后,我们到达Triggers选项卡,这也是配置 Xcode 持续集成机器人的最后一个选项卡。 这是 Xcode Server 武器库中最强大的工具。 对于初学者,我喜欢添加以下两个命令作为预集成脚本:

#!/bin/sh set printenv
第一个打印 Xcode Server 在当前集成运行中使用的所有变量及其值。 第二个打印所有环境变量及其值。 正如预期的那样,这有助于调试您的脚本,因此我恰当地将其命名为“调试信息”。
请记住,我们提到我们需要确保上传到 App Store Connect 的每个构建都需要具有唯一的构建版本和内部版本号对。 我们可以使用内置的 PlistBuddy 工具,但我们还需要一种方法来拥有唯一的内部版本号。 在 Xcode Server 集成期间始终存在的一件事——并且也是方便地唯一的——是集成编号,因为它是自动递增的。 我们将创建另一个预集成脚本,名为“set build number”,内容如下,以确保我们每次都有一个唯一的 build number:
#!/bin/sh buildNumber=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "${PROJECT_DIR}/${INFOPLIST_FILE}") buildNumber=$XCS_INTEGRATION_NUMBER /usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "${PROJECT_DIR}/${INFOPLIST_FILE}"
如果您正在使用 CocoaPods 并选择不将 Pods 目录提交到您的 DVCS,您还应该包含一个包含以下内容的预集成脚本:
#!/bin/sh cd $XCS_PRIMARY_REPO_DIR pod install
第 10 步:我们几乎完成了,但我们尚未指定要将构建上传到 AppStore Connect 的任何地方或哪个帐户。 为此,我们将添加后集成脚本和另一个内置工具,称为 Application Loader。 将以下内容放入脚本中:
#!/bin/sh /Applications/Xcode.app/Contents/Applications/Application\ Loader.app/Contents/Frameworks/ITunesSoftwareService.framework/Support/altool --upload-app -f $XCS_PRODUCT -u $TESTFLIGHT_USERNAME -p $TESTFLIGHT_PASSWORD
$XCS_PRODUCT
是一个 Xcode 服务器变量,它包含在当前集成运行中创建的应用程序的路径。 但是, $TESTFLIGHT_USERNAME
和$TESTFLIGHT_PASSWORD
既不是系统变量,也不是 Xcode 服务器变量。 这些必须由您设置并具有您的 Apple ID 和密码的值。 不幸的是,Apple 已停止支持为 AppStore Connect 构建上传生成 API 密钥。 由于这是机密信息,因此最佳做法是直接在 Mac 服务器上(假设它是您自己的)将其设置为环境变量,而不是在 Xcode Server 机器人配置中。
Xcode 服务器分发
Xcode Server 分发机器人实际上使用与 App Store Connect 分发相同的配置,但集成后脚本除外。 但是,下载应用程序并安装它仍然很棘手。 您仍然必须确保您为应用程序签名的配置文件允许该应用程序安装在您使用的设备上。
准备好之后,您需要在 iOS 设备上打开 Safari 并导航到服务器的 Xcode Server Web 仪表板。 例如,如果您的服务器名称是“Mac 服务器”,如果您与服务器位于同一网络上,您可以在“mac-server-name.local/xcode”中找到它。 在那里,您会找到所有 Xcode 机器人的列表以及它们最近集成的统计信息。
选择已构建您要下载的应用程序的应用程序。 在接下来的屏幕上,您将有两个按钮 - Install和Profile 。 如果这是您第一次从该服务器下载,您必须单击配置文件以将其证书添加到受信任来源列表中。 之后,单击同一页面上的安装按钮,您将看到 iOS 确认对话框“您确定要在您的设备上安装 * 吗?” 单击Yes进行确认,您的应用程序将被安装并可以从主屏幕运行。
对于iOS 10.3 及更高版本,它可能因“无法连接到 *.local”而失败的一个原因是,必须在测试设备的设置中手动信任自签名证书。
按着这些次序:
第 1 步:从 iPhone 上的 Xcode 服务器的机器人页面安装自签名证书。
第 2 步:转到 iPhone 的设置 > 通用 > 关于 > 证书信任设置。
第 3 步:在ENABLE FULL TRUST FOR ROOT CERTIFICATES部分下找到您服务器的自签名证书,然后打开开关。
第 4 步:返回 Xcode Server 上的 bot 集成页面,单击Install 。
Xcode 服务器自动应用程序测试
Xcode Server 的另一个重要用途是自动应用程序测试,无论是单元测试还是 UI 测试。 为此,您需要为您的项目设置适当的目标。 也就是说,您需要有一个运行单元或 UI 测试的目标,具体取决于您的目标。
设置过程与上一个相同,但我们将选择不同的选项。 第一个主要区别在于配置选项卡。 显然,我们将选中“分析”和“测试”框,因为这是我们的主要目标。 我还建议不要使用此机器人存档或导出产品。 可以使用相同的机器人配置同时实现测试和分发。 但是,这两种情况的输出和时间表不同。 分发通常在周期结束时运行。
无论您是在 Scrum 还是看板或其他框架中工作,都应该有一个预定义的时间驱动或事件驱动的周期,在该周期结束时,您应该有导出和可用的产品。 另一方面,您应该在每次提交时运行您的测试机器人,因为它是您抵御回归的第一道防线。 由于测试机器人显然运行得更频繁,将这两个机器人合并为一个可能会很快耗尽服务器上的磁盘空间。 而且每次集成还需要更多时间才能完成。
有了这个,我们将转到“计划”选项卡,我们已经在上一段中解决了这个问题。 因此,下一个感兴趣的主题是代码签名。 请注意,即使您的测试目标可能在您的项目设置页面中声明它不需要配置文件,您也应该将其设置为使用与主机应用程序相同的团队和签名证书。 如果您想在 iOS 设备上而不是在模拟器上测试您的应用程序,这是必需的。 如果是这种情况,您还需要确保用于测试的 iOS 设备不会因为不活动而被锁定,因为这可能会导致您的集成运行无限期挂起而不通知您。
现在我们在不需要具体解释的“设备”选项卡上。 只需选择一个、多个或所有要测试代码的设备(iOS 和模拟器)。 您还可以检查是否在多个设备上并行或按顺序运行测试。 要进行设置,您应该考虑您的项目需求(无论您是针对一组特定设备还是所有受支持的 iOS 设备)以及服务器的硬件资源。
在参数选项卡上。 无需明确指定任何内容,因为我们只会使用内置环境变量。
最后,在Triggers选项卡上,我们将介绍一个预集成和一个集成后脚本。 第一个只是为了帮助我们调试,以防我们遇到一些问题。 它实际上是我们已经使用过的:
#!/bin/sh set printenv
第二个是在我们的一个或多个测试在当前集成中失败的情况下通知我们的。 确保将其设置为仅在测试失败时运行。 并输入以下内容:
#!/bin/sh echo "$XCS_TEST_FAILURE_COUNT test(s) failed for $XCS_BOT_NAME bot on build $XCS_INTEGRATION_NUMBER" echo "You can see bot integration at:" echo "https://$HOSTNAME/xcode/bots/$XCS_BOT_TINY_ID/integrations/$XCS_INTEGRATION_TINY_ID"
这里有几件事需要解释。 首先,$HOSTNAME 变量存储以下格式的值:computer-name.local。 显然,只有当您可以通过本地网络访问该服务器时,该链接才会起作用。 此外,当您访问此链接时,您很可能会从浏览器收到安全警告,因为它是到无法信任的目的地的 https 连接。 最后,这只是您的“测试失败”脚本的起点。 您可以向整个开发团队发送电子邮件,或通过 API 请求或您认为最合适和最有效的任何其他方式打开 JIRA 问题。
包起来
希望本文能鼓励您花时间探索 Xcode Server 的功能,而不仅仅是构建一个应用程序。 虽然这篇文章可能无法完全按照您想要或期望的方式帮助您,但其目的是向您介绍一种使用内置环境和 Xcode Server 变量实现更高级别自动化的开放方式。
有很多第三方服务支持更多功能,可以为你做更多的工作,包括 Fabric、Bluepill 和 Fastlane。 但是,不可避免地,依赖第三方会为您的项目引入新的依赖关系,并且有时需要简单、有时复杂的设置和配置。 此处描述的技术只需要每台 Mac 上已经安装的工具,因此除了配置将运行您的自动构建的机器人之外,它不需要设置时间!