构建和交付 iOS 应用程序的功能

在这篇文章中,我们分享了Plarium Krasnodar工作室在调试CI/CD过程中积累的组装和交付iOS应用程序给用户的经验。

构建和交付 iOS 应用程序的功能

训练

每一个以某种方式参与苹果设备应用程序开发的人都已经意识到基础设施的有争议的便利性。 困难无处不在:从开发人员配置文件菜单到调试和构建工具。

互联网上有很多关于“基础知识”的文章,因此我们将尽力突出主要内容。 以下是成功构建应用程序所需的内容:

  • 开发者帐户;
  • 充当构建服务器的基于 macOS 的设备;
  • 生成的 开发者证书,这将进一步用于签署应用程序;
  • 创建具有独特的应用程序 ID (需要注意Bundle Identifier的重要性,因为使用通配符ID会导致无法使用应用程序的许多功能,例如:关联域、推送通知、Apple Sign In等);
  • 轮廓 应用程序签名。

必须通过任何 macOS 设备上的钥匙串生成开发人员证书。 证书的类型非常重要。 根据应用程序环境(开发、QA、登台、生产)的不同(开发或分发),应用程序签名配置文件的类型也会有所不同。

型材的主要类型:

  • 开发 - 用于签署开发团队的应用程序,使用开发证书(类型名称 iPhone Developer:XXXXX);
  • Ad Hoc - 用于签署测试应用程序并由 QA 部门进行内部验证,使用开发人员的分发证书(类型名称 iPhone Distribution:XXXXX);
  • App Store - 通过 TestFlight 进行外部测试的发布版本并上传到 App Store,使用开发人员的分发证书。

生成 Development 和 Ad Hoc 配置文件时,还会指示 设备清单,您可以在其上安装一个版本,该版本允许您进一步限制用户的访问。 App Store 配置文件中没有设备列表,因为内测期间的访问控制由 TestFlight 处理,这将在稍后讨论。

为了清楚起见,您可以用下表的形式展示开发者的个人资料。 这使得我们更容易理解组装需要哪些参数以及从哪里获取它们。

构建和交付 iOS 应用程序的功能

装配

为了更容易地按项目和环境分离程序集,我们使用配置文件名称,例如 ${ProjectName}_${Instance},即项目名称+实例(取决于应用环境:Dev、QA、GD、Staging、Live等)。

当导入到构建服务器时,配置文件将其名称更改为唯一 ID 并移动到文件夹 /Users/$Username/Library/MobileDevice/Provisioning Profiles (其中 $Username 对应于构建服务器的用户帐户名)。

构建 *.ipa 文件有两种方法 - 传统 (PackageApplication) 和现代(通过 XcAchive 创建和导出)。 第一种方法被认为已过时,因为自版本 8.3 以来,应用程序文件打包模块已从 Xcode 发行版中删除。 要使用它,您需要将模块从旧的 Xcode(版本 8.2 及更早版本)复制到该文件夹​​:
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/

然后运行命令:

chmod +x /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/*

接下来需要收集应用程序的*.app文件:

xcodebuild 
-workspace $ProjectDir/$ProjectName.xcworkspace 
-scheme $SchemeName 
-sdk iphoneos 
build 
-configuration Release 
-derivedDataPath build 
CODE_SIGN_IDENTITY=”$DevAccName”
PROVISIONING_PROFILE=”$ProfileId”
DEPLOYMENT_POSTPROCESSING=YES 
SKIP_INSTALL=YES 
ENABLE_BITCODE=NO

在哪里:

-workspace — 项目文件的路径。

-scheme ——项目中指定的所使用的方案。

-derivedDataPath — 下载已组装应用程序的路径 (*.app)。

CODE_SIGN_IDENTITY — 开发者帐户名称,可在 Keychain 中验证(iPhone 开发者:XXXX XXXXXXX,括号内不含 TeamID)。

构建和交付 iOS 应用程序的功能

PROVISIONING_PROFILE — 用于签署应用程序的配置文件 ID,可以通过以下命令获取:

cd "/Users/$Username/Library/MobileDevice/Provisioning Profiles/" && find *.mobileprovision -type f | xargs grep -li ">${ProjectName}_${Instance}<" | sed -e 's/.mobileprovision//'

如果应用程序使用附加配置文件(例如,用于推送通知),则代替 PROVISIONING_PROFILE 表明:

APP_PROFILE=”$AppProfile” 
EXTENSION_PROFILE=”$ExtProfile” 

接下来,生成的 *.app 文件应打包为 *.ipa。 为此,您可以使用如下命令:

/usr/bin/xcrun --sdk iphoneos PackageApplication 
-v $(find "$ProjectDir/build/Build/Products/Release-iphoneos" -name "*.app") 
-o "$ProjectDir/$ProjectName_$Instance.ipa"

然而,从苹果的角度来看,这种方法被认为是过时的。 通过从应用程序存档导出来获取*.ipa 是相关的。

首先,您需要使用以下命令收集存档:

xcodebuild 
-workspace $ProjectDir/$ProjectName.xcworkspace 
-scheme $SchemeName 
-sdk iphoneos 
-configuration Release 
archive 
-archivePath $ProjectDir/build/$ProjectName.xcarchive 
CODE_SIGN_IDENTITY=”$DevAccName” 
PROVISIONING_PROFILE=”$ProfileId”
ENABLE_BITCODE=NO 
SYNCHRONOUS_SYMBOL_PROCESSING=FALSE

差异在于装配方法和选项 SYNCHRONOUS_SYMBOL_PROCESSING,这会在构建时禁用符号卸载。

接下来我们需要生成一个包含导出设置的文件:

ExportSettings="$ProjectDir/exportOptions.plist"

cat << EOF > $ExportSettings
<?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>uploadBitcode</key>
<false/>
<key>uploadSymbols</key>
<false/>
<key>method</key>
<string>$Method</string>
<key>provisioningProfiles</key>
<dict>
<key>$BundleID</key>
<string>$ProfileId</string>
</dict>
<key>signingCertificate</key>
<string>$DevAccName</string>
<key>signingStyle</key>
<string>manual</string>
<key>stripSwiftSymbols</key>
<true/>
<key>teamID</key>
<string>$TeamID</string>
<key>thinning</key>
<string><none></string>
</dict>
</plist>
EOF

在哪里:

$Method — 交付方法,对应于应用程序签名配置文件类型,即对于 Development,该值将为development,对于 Ad Hoc - ad-hoc,对于 App Store - app-store。

$BundleID — 应用程序 ID,在应用程序设置中指定。 您可以使用命令检查:

defaults read $ProjectDir/Info CFBundleIdentifier

$DevAccName и $ProfileId — 之前使用的开发者名称和签名配置文件 ID 设置,必须与导出设置中的值匹配。

$TeamID — 开发者姓名后括号内的十位 ID,例如:iPhone 开发者:……(XXXXXXXXXX); 可以在钥匙串中查看。

接下来,使用导出命令,我们获得必要的 *.ipa 文件:

xcodebuild 
-exportArchive 
-archivePath $ProjectDir/build/$ProjectName.xcarchive 
-exportPath $ProjectDir 
-exportOptionsPlist $ExportSettings

物流运输

现在需要将收集到的文件交付给最终用户,即安装在设备上。

有许多用于分发开发和 Ad Hoc 构建的服务,例如 HockeyApp、AppBlade 等,但在本文中我们将讨论用于分发应用程序的独立服务器。

安装 iOS 应用程序分两个阶段进行:

  1. 通过项目服务接收应用程序安装清单。
  2. 根据清单中指定的信息通过 HTTPS 安装 *.ipa 文件。

因此,我们首先需要使用以下命令生成安装清单(文件类型 *.plist):

cat << EOF > $manifest
<?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>items</key>
<array>
<dict>
<key>assets</key>
<array>
<dict>
<key>kind</key>
<string>software-package</string>
<key>url</key>
<string>$ipaUrl</string>
</dict>
</array>
<key>metadata</key>
<dict>
<key>bundle-identifier</key>
<string>$BundleID</string>
<key>bundle-version</key>
<string>$AppVersion</string>
<key>kind</key>
<string>software</string>
<key>title</key>
<string>$ProjectName_$Instance</string>
<key>subtitle</key>
<string>$Instance</string>
</dict>
</dict>
</array>
</dict>
</plist>
EOF

如您所见,清单包含构建应用程序涉及的几乎所有参数。

应用程序版本($AppVersion) 可以使用以下命令进行检查:

defaults read $ProjectDir/Info CFBundleVersion

参数 $ipaUrl 包含下载 *.ipa 文件的直接链接。 从 iOS 第七版开始,应用程序必须通过 HTTPS 安装。 在第八个版本中,清单的格式略有变化:带有应用程序图标设置的块,例如

<images>
   <image>...</image>
</images>

因此,要安装该应用程序,一个带有如下链接的简单 HTML 页面就足够了:

itms-services://?action=download-manifest&url=https://$ServerUrl/$ProjectName/$Instance/iOS/$AppVersion/manifest.plist

为了满足开发和测试部门的需求,Plarium 创建了自己的构建安装应用程序,它为我们提供了:

  • 自治和独立,
  • 通过“临时”动态创建的链接集中访问控制和安全安装应用程序,
  • 可扩展的功能(即,开发团队在必要时可以将缺失的功能集成到现有应用程序中)。

测试

现在我们将讨论使用应用程序的预发布测试 TestFlight.

下载所需的条件是 App Store 签名配置文件的类型以及生成的 API 密钥的存在。

有多种方式下载该应用程序:

  • 通过 Xcode(组织者),
  • 通过阿尔工具,
  • 通过旧版本 Xcode 的应用程序加载器(现在的 Transporter)。

自动下载使用的是altool,它也有两种授权方式:

  • 应用程序专用密码,
  • API 密钥。

最好使用 API 密钥下载应用程序。

要获取 API 密钥,请访问 链接 并生成密钥。 除了 *.p8 格式的密钥本身之外,我们还需要两个参数:IssuerID 和 KeyID。

构建和交付 iOS 应用程序的功能

接下来,将下载的密钥导入到构建服务器:

mkdir -p ~/.appstoreconnect/private_keys
mv ~/Downloads/AuthKey_${KeyID}.p8 ~/.appstoreconnect/private_keys/

在将应用程序上传到 TestFlight 之前,您需要验证应用程序,我们使用以下命令执行此操作:

xcrun altool 
--validate-app 
-t ios 
-f $(find "$ProjectDir" -name "*.ipa") 
--apiKey “$KeyID” 
--apiIssuer “$IssuerID” 

哪里 apiKey и apiIssuer 具有来自 API 密钥生成页面的字段值。

接下来,验证成功后,我们使用以下命令加载应用程序 --upload-app 具有相同的参数。

该应用程序将在一两天内由 Apple 进行测试,然后可供外部测试人员使用:他们将通过电子邮件收到安装链接。

通过 altool 下载应用程序的另一种方法是使用应用程序专用密码。

要获取应用程序专用密码,您需要访问 链接 并在安全部分生成它。

构建和交付 iOS 应用程序的功能

接下来,您应该使用此密码在钥匙串中创建构建服务器记录。 从 Xcode 11 版本开始,可以使用以下命令完成此操作:

xcrun altool --store-password-in-keychain-item "Altool" -u "$DeveloperName" -p $AppPswd

在哪里:

$DeveloperName — 用于登录 Apple 服务的 iOS 开发者帐户的名称。

$AppPswd — 生成的应用程序专用密码。

接下来,我们获取asc-provider参数的值,并使用命令检查密码导入是否成功:

xcrun altool --list-providers -u "$DeveloperName" -p "@keychain:Altool"

我们得到输出:

Provider listing:
- Long Name - - Short Name -
XXXXXXX        XXXXXXXXX

如您所见,所需的短名称值 (asc-provider) 与我们在构建应用程序时使用的 $TeamID 参数一致。

要验证应用程序并将其加载到 TestFlight 中,请使用以下命令:

xcrun altool 
--(validate|upload)-app   
-f $(find "$ProjectDir" -name "*.ipa") 
-u "$DeveloperName" 
-p "@keychain:Altool" 

作为参数值 -p 你可以取这个值 $AppPswd 以未加密(显式)形式。

不过,前面已经提到,从性能的角度来看,最好选择 API Key 进行 altool 授权,因为不同版本的 Xcode 都会存在一定的问题(“看不到”Keychain、上传时授权错误等)。

事实上,仅此而已。 我希望每个人都能在 App Store 中成功构建并顺利发布。

来源: habr.com

添加评论