如何对包含扩展的未签名.xcarchive或.ipa文件进行有效签名?
优先选择未签名的.xcarchive作为签名基材,相比处理.ipa文件出错概率更低。
前置检查项
- 确认两份provisioning profile的Bundle ID分别与主应用、扩展的Bundle ID完全匹配,且均包含你当前使用的Distribution证书公钥
- 确认钥匙串中的Distribution证书处于有效信任状态,无过期、权限报错问题
- 提前将两份provisioning profile重命名为易识别的名称,例如
main.mobileprovision(主应用)、ext.mobileprovision(扩展)
步骤1:清理并替换xcarchive内的签名相关文件
右键点击.xcarchive文件,选择「显示包内容」,进入Products/Applications/目录找到.app主应用包,再次右键选择「显示包内容」:
- 删除主.app包内的
_CodeSignature文件夹(旧签名残留) - 进入主.app包内的
PlugIns目录,找到扩展对应的.appex包,同样删除其内部的_CodeSignature文件夹 - 将
ext.mobileprovision放到.appex包根目录,重命名为embedded.mobileprovision - 回到主.app包根目录,将
main.mobileprovision放到该目录,重命名为embedded.mobileprovision
步骤2:生成对应entitlements权限文件
手动签名失败90%以上是因为遗漏了和provisioning profile匹配的权限文件,执行以下命令分别提取主应用和扩展的权限文件:
提取主应用权限
security cms -D -i main.mobileprovision > main_full.plist /usr/libexec/PlistBuddy -x -c 'Print:Entitlements' main_full.plist > main.entitlements
提取扩展权限
security cms -D -i ext.mobileprovision > ext_full.plist /usr/libexec/PlistBuddy -x -c 'Print:Entitlements' ext_full.plist > ext.entitlements
注意:如果应用使用了共享组、推送、健康等特殊权限,需确认两个entitlements文件内的权限配置和profile完全一致
步骤3:按顺序执行签名
签名顺序必须遵循先签所有嵌套扩展、最后签主应用的规则,顺序错误会直接导致签名失效。
首先执行命令获取证书的完整标识:
security find-identity -v -p codesigning
从输出结果中复制你要用的Distribution证书完整名称,格式类似iPhone Distribution: XXX Co., Ltd. (XXXXXXXXXX)。
签名扩展
codesign -f -s "你的证书完整名称" --entitlements ext.entitlements 扩展.appex的绝对路径
签名主应用
codesign -f -s "你的证书完整名称" --entitlements main.entitlements 主.app的绝对路径
签名完成后可执行验证命令确认签名有效:
codesign -vv 主.app的绝对路径
无报错即为签名正常。
步骤4:导出ipa
方式1:打开Xcode -> Window -> Organizer,选择处理完成的xcarchive,点击「Distribute App」按指引选择对应分发渠道导出即可。
方式2:使用命令行导出,提前准备好符合你分发需求的exportOptions.plist,执行命令:
xcodebuild -exportArchive -archivePath 你的.xcarchive绝对路径 -exportPath 导出目录路径 -exportOptionsPlist exportOptions.plist
可选:使用.ipa文件签名的补充说明
如果你选择用未签名的.ipa文件处理,仅需先将ipa解压拿到Payload文件夹,后续操作和上述步骤完全一致,签名完成后直接将Payload文件夹压缩为zip,修改后缀为ipa即可。
注意压缩时不要把Payload外层的目录打包进压缩包,否则ipa无法正常安装。
常见失败原因排查
- 签名顺序错误,未先签署扩展组件
- entitlements文件和provisioning profile的权限配置不匹配
- 钥匙串中存在多个同名证书,签名时调用了错误的证书
- 主应用和扩展的provisioning profile用反,或Bundle ID不匹配
内容的提问来源于stack exchange,提问作者Andrea Mario Lufino

