iOS 签名报错与 ipa 安装失败,16 条常见错误及解决办法
签名问题会在三个时间点暴露。构建时 KXBuild 检查证书和描述文件,报错文字和 Xcode 一致。安装时手机拒绝安装。打开时 iOS 拦住不让运行。本文按这三个阶段整理了 16 条最常见的报错,每条写清现象、原因和解决办法,最后给出一套排查顺序。证书和描述文件怎么放、构建时怎么选,先看证书与签名。
先弄清签名用到的三样东西
几乎所有签名报错都是下面三样东西之间对不上。
- 证书(.p12) 包含证书和私钥。Apple Development 用于真机调试,Apple Distribution 用于 App Store、TestFlight、Ad Hoc 和企业分发。只有 .cer 没有私钥不能签名。
- App ID 即 Bundle ID 加上开通的能力(推送、iCloud、Sign in with Apple 等),在 Apple Developer 后台的 Identifiers 页管理。
- 描述文件(.mobileprovision) 把团队、App ID、允许使用的证书、允许安装的设备(Development 和 Ad Hoc 类型才有)和能力绑在一起,有效期一年。
KXBuild 从证书目录读取这些文件,工程根目录下的 keychain 只对该工程生效,KXBUILD_HOME 下的 keychain 所有工程共用,放法见放入证书目录。证书目录里的文件读不出来时,构建日志会出现以 keychain: 开头的警告,排错时先看这几行。
在 Windows 上查看描述文件内容
描述文件是签过名的 plist,用 OpenSSL 可以解出来。Git for Windows 自带 OpenSSL,在 Git Bash 中直接运行 openssl,在 PowerShell 中用完整路径。
1& "C:\Program Files\Git\mingw64\bin\openssl.exe" smime -inform DER -verify -noverify -in .\keychain\MyApp_Dev.mobileprovision -out profile.plist
用编辑器打开 profile.plist,排错时主要看这几个键。
| 键 | 内容 |
|---|---|
| Name | 描述文件名,手动签名时 PROVISIONING_PROFILE_SPECIFIER 填的就是它 |
| TeamIdentifier | 团队 ID |
| Entitlements → application-identifier | 团队 ID 加 Bundle ID,通配 App ID 以 * 结尾 |
| Entitlements 其余键 | 开通的能力,例如 aps-environment 代表推送 |
| ProvisionedDevices | 允许安装的设备 UDID 列表,App Store 类型没有这一项 |
| ExpirationDate | 到期时间 |
构建时的报错
No profiles for ‘com.example.myapp’ were found
现象 构建停在签名阶段,完整信息类似 No profiles for 'com.example.myapp' were found: Xcode couldn't find any iOS App Development provisioning profiles matching 'com.example.myapp'.,日志里还会列出搜索过的证书目录。
原因 工程用的是自动签名,KXBuild 按 Bundle ID 和团队在证书目录里找描述文件,一个也没匹配上。常见的有四种情况。描述文件没放进证书目录,或放进了另一个工程的 keychain。描述文件已过期。类型不对,Debug 用 Apple Development 证书要 Development 描述文件,Release 用 Apple Distribution 证书要 App Store 或 Ad Hoc 描述文件。工程里有 Widget、通知扩展这类扩展 target,它们的 Bundle ID(如 com.example.myapp.widget)各自需要一个描述文件,报错里的 Bundle ID 就是扩展的。
解决 在 Apple Developer 后台为报错中的 Bundle ID 生成对应类型的描述文件,下载后放进证书目录。确认 target 的 Bundle ID 和后台的 App ID 一致,可以在工程设置编辑器的 General → Identity 查看。开发阶段没有开通特殊能力的,可以用通配 App ID(如 com.example.*)的 Development 描述文件覆盖主 App 和所有扩展。
Provisioning profile “…” has app ID “…”, which does not match the bundle ID “…”
现象 工程用手动签名,构建时报描述文件的 App ID 和 Bundle ID 不一致。
原因 PROVISIONING_PROFILE_SPECIFIER 指定的描述文件是给另一个 Bundle ID 生成的。改过 Bundle ID、从别的工程复制签名设置、或者 Bundle ID 里有 $(PRODUCT_NAME) 这类变量解析出来的值和预想不同,都会出现。
解决 以报错里的 bundle ID 为准,在后台生成匹配它的描述文件;或者把工程的 Bundle ID 改回描述文件对应的值。不确定最终值时用 kxbuild project info 查看每个 target 解析后的 Bundle ID。
1kxbuild project info .\MyApp.xcodeproj
Provisioning profile “…” doesn’t include signing certificate “…”
现象 证书目录里有证书,也有描述文件,构建时报描述文件不包含这张证书。
原因 生成描述文件时勾选的证书不是现在用的这张。最常见的是证书过期或丢了私钥后重新申请了证书,描述文件还是旧的;或者团队里每人一张 Development 证书,描述文件只勾了别人的。
解决 在后台 Profiles 页编辑这个描述文件,勾上当前证书,保存后重新下载,替换证书目录里的旧文件。Development 描述文件可以同时勾选团队所有人的证书,一份文件大家共用。
No signing certificate matching ‘…’ found
现象 报 No signing certificate matching 'Apple Distribution' found,或带团队的 No certificate for team '…' matching '…' found。
原因 工程的 CODE_SIGN_IDENTITY 要求某类证书,DEVELOPMENT_TEAM 要求某个团队,证书目录里没有同时满足两者、未过期、带私钥的证书。已过期的证书会被跳过,所以证书过期后通常报的就是这一条。
解决 放入对应类型和团队的 .p12。只是这次构建想换证书时,用 -D 临时覆盖,不改工程文件,详见临时覆盖构建设置。
1kxbuild build .\MyApp.xcodeproj -c Release -D CODE_SIGN_IDENTITY="Apple Distribution" -D DEVELOPMENT_TEAM=ABCDE12345
keychain: xxx.p12: pkcs12: decryption password incorrect
现象 构建日志开头出现这条警告,随后多半接着报 No signing certificate matching。
原因 password.properties 里没有这张证书的密码,或者密码不对,或者文件名写得和实际的 .p12 不一致(区分大小写,要带 .p12 后缀)。
解决 每行一张证书,写成 文件名.p12=密码,密码不加引号。忘了密码的,用原来的私钥和 .cer 重新合成一个 .p12 并设新密码。
1development.p12=123456
2distribution.p12=123456
另一条相近的警告是 has no private key; codesign will fail unless the .p12 is re-exported with its key,说明这个 .p12 里只有证书没有私钥,要从生成 CSR 的那台电脑或 Mac 钥匙串里连同私钥重新导出。
Provisioning profile “…” doesn’t include the Push Notifications capability
现象 构建报描述文件不包含某项能力,能力名可能是 Push Notifications、iCloud、Sign in with Apple、Associated Domains、App Groups 等,有时后面还跟一句 doesn't include the aps-environment entitlement。
原因 工程的 entitlements 文件(CODE_SIGN_ENTITLEMENTS 指向的 .entitlements)申请了这项能力,但 App ID 没有开通,或者开通之后没有重新生成描述文件。描述文件生成那一刻就把能力固定下来了,之后在 App ID 上新开的能力不会自动进入旧文件。
解决 在后台 Identifiers 页打开这个 App ID,勾选对应能力并保存。然后到 Profiles 页编辑该 App ID 的每一个描述文件(Development、Ad Hoc、App Store 各一份),保存并重新下载。通配 App ID 不能开通推送等大部分能力,用到这些能力的 App 要改用精确 App ID。反过来,如果并不需要这项能力,就从 entitlements 文件里删掉对应的键。
安装到手机时的报错
用 kxbuild build --install、VS Code 中的「构建并运行」或 kxdevice install 安装时,手机拒绝安装会把 iOS 返回的原因打印出来,签名类问题的前缀是 app not properly signed for this device: ApplicationVerificationFailed,括号里是具体原因。
doesn’t include the currently selected device
现象 Xcode 在构建时就会报 Provisioning profile "…" doesn't include the currently selected device。KXBuild 构建阶段不绑定设备,同样的问题在安装时出现,表现为下一条 A valid provisioning profile for this executable was not found。
原因 Development 或 Ad Hoc 描述文件里的 ProvisionedDevices 没有这台手机的 UDID。换了新手机、借同事的手机测试时最常遇到。
解决 先拿到 UDID。手机连上电脑后运行下面的命令,第一列就是 UDID,设备连接问题见设备准备。
1kxdevice device list
在后台 Devices 页注册这个 UDID,再到 Profiles 页编辑描述文件,勾上新设备,保存并重新下载,替换证书目录里的旧文件后重新构建。只注册设备不重新下载描述文件是没用的。
A valid provisioning profile for this executable was not found
现象 安装失败,信息类似 ApplicationVerificationFailed (Failed to verify code signature of … : 0xe8008015 (A valid provisioning profile for this executable was not found.))。
原因 手机认为包里的描述文件不允许它安装。有四种常见情况。描述文件不含这台手机的 UDID。用 App Store 描述文件签的包直接装真机,App Store 类型只能经 TestFlight 或 App Store 安装。描述文件或证书已过期、证书已被吊销。包是手工重签或改过内容的,描述文件和签名对不上。
解决 调试用 Debug 配置、Apple Development 证书和包含该设备的 Development 描述文件。给测试人员装 Release 包用 Ad Hoc 描述文件,同样要包含设备 UDID,见发布与上架中的「不上架,直接分发」。想确认包里用的是哪份描述文件,用 kxdevice provisioning list 看手机上已安装的描述文件,或者按上文解出证书目录里那份,核对 ProvisionedDevices 和 ExpirationDate。
The executable was signed with invalid entitlements
现象 安装失败,错误码 0xe8008016,信息是 The executable was signed with invalid entitlements。
原因 签进包里的 entitlements 超出了描述文件允许的范围。KXBuild 构建时已经按描述文件检查过主 App,这条错误多见于扩展 target 用了另一个团队或缺少对应能力的描述文件、手工改过 entitlements 后重签的包、第三方工具重签的包。
解决 用 KXBuild 重新构建整个工程,而不是重签旧包,保证主 App 和每个扩展都用同一团队、各自 Bundle ID 对应的描述文件签名。某个扩展需要推送或 App Groups 时,它自己的 App ID 也要开通并重新生成描述文件。
DeviceOSVersionTooLow,iOS 版本低于部署目标
现象 安装失败并提示 DeviceOSVersionTooLow,在 Xcode 里对应 The iPhone's iOS … doesn't match MyApp.app's iOS … deployment target。通过网页或其他工具安装时,手机上只显示「无法安装」。
原因 工程的 iOS Deployment Target(IPHONEOS_DEPLOYMENT_TARGET)高于手机的系统版本。新建工程模板和一些第三方库会把部署目标设得比较新。
解决 能升级手机系统就升级。要支持旧系统,就把部署目标调低,前提是代码和依赖库没有用到更高版本才有的 API。可以在工程设置编辑器 General → Deployment 修改,或者用命令行改。
1kxbuild project add-setting -k IPHONEOS_DEPLOYMENT_TARGET -v 15.0 -t MyApp -P .\MyApp.xcodeproj
用 CocoaPods 的工程还要同时调低 Podfile 里的 platform :ios,重新 pod install,见 CocoaPods。
MismatchedApplicationIdentifierEntitlement,升级安装失败
现象 手机上已经有这个 App,再安装新构建时失败,信息里有 MismatchedApplicationIdentifierEntitlement 或 Upgrade's application-identifier entitlement string … does not match installed application's。
原因 手机上的旧版本是另一个团队签名的,或者 App ID 前缀不同。换了开发者账号、从公司账号换成个人账号时会遇到。
解决 先卸载旧版本再安装。卸载后 App 的本地数据会丢失。
1kxdevice apps uninstall com.example.myapp
无法安装此 App,ipa 分发安装失败
现象 测试人员通过网页链接、第三方分发平台或设备管理工具安装 ipa,进度走完后提示「无法安装」或图标一直灰色。
原因 这类途径只显示笼统的失败,真实原因通常就是前面几条之一。设备不在 Ad Hoc 描述文件里最常见,其次是用 Development 或 App Store 描述文件签的包、iOS 版本低于部署目标、证书已吊销。
解决 用数据线把手机连到电脑,运行 kxdevice install MyApp.ipa,它会打印 iOS 返回的具体原因,再对照本文对应的小节处理。发给外部测试人员的包,比 Ad Hoc 更省事的做法是走 TestFlight,不用收集 UDID。
打开 App 时的问题
需要开发者模式(Developer Mode)
现象 App 装上了,点开弹出「需要开发者模式」,或者调试时连不上 debugserver。
原因 iOS 16 起运行开发证书签名的 App、进行调试都要打开开发者模式。
解决 手机「设置 → 隐私与安全性 → 开发者模式」打开,手机会重启,重启后解锁确认。这个开关要在手机连接过电脑之后才出现。设置里找不到时,用 kxdevice 让它显示出来,或者直接打开,详见 devmode。
1kxdevice devmode reveal
2kxdevice devmode enable
未受信任的开发者(Untrusted Developer)
现象 点开 App 弹出「未受信任的企业级开发者」或「未受信任的开发者」,只能点取消。
原因 企业账号 In-House 证书签名的 App,以及免费 Apple ID 签名的 App,第一次打开前都要用户手动信任。加入 Apple Developer Program 的账号签的 Development 和 Ad Hoc 包一般不会出现这个提示。
解决 手机「设置 → 通用 → VPN 与设备管理」,在「企业级 App」或「开发者 App」下点开对应的开发者名称,点「信任」。信任时手机要能联网,iOS 会在线验证证书。
证书过期或被吊销
现象 构建时报 No signing certificate matching 或 No profiles for … were found;已经装在手机上的开发版、Ad Hoc 版或企业版 App 突然打不开,闪退或提示无法验证。
原因 证书有效期一年(企业证书时间不同),描述文件最长一年,并且会随着它包含的证书过期或吊销一起失效。有人在后台点了 Revoke,或者证书数量到上限时删掉了旧证书,都会让用它签名的包失效。已上架 App Store 的版本不受发布证书过期影响。
解决 在后台 Certificates 页查看证书状态。过期或吊销的,用新的 CSR 申请一张新证书(也可以沿用原来的私钥生成 CSR),合成新的 .p12 放进证书目录,然后到 Profiles 页编辑所有相关描述文件,改选新证书并重新下载,最后重新构建、重新安装。团队共用发布证书时,吊销前先确认没有其他人正在用它出包。
Apple 后台的限制
设备数量已达上限,无法注册新设备
现象 在后台 Devices 页添加设备时提示数量已满,按钮不可用。
原因 每个会员年度内,每类设备(iPhone、iPad、Apple Watch、Apple TV、Mac 等)最多注册 100 台。删除设备并不会立刻腾出名额,被删的设备在本年度内仍然计数。
解决 等会员续费时,Apple 会给一次清理机会,届时停用不再使用的设备,腾出的名额在新年度生效。在那之前,外部测试改用 TestFlight,它不占设备名额。内部测试尽量复用已注册的设备。
排查顺序
遇到签名或安装问题,按下面的顺序检查,多数情况在前三步就能定位。
- 看构建日志开头以
keychain:开头的警告,确认每张 .p12 都读出来了,密码和私钥没有问题。 - 核对证书。类型(Development 还是 Distribution)、团队、有效期都要和工程签名设置一致,签名设置在工程设置编辑器 General → Signing。
- 核对描述文件。用 OpenSSL 解出来看 application-identifier 是否匹配每个 target 的 Bundle ID,类型是否对应当前配置,能力是否齐全,是否过期,DeveloperCertificates 是否包含当前证书。
- 核对设备。Development 和 Ad Hoc 描述文件的 ProvisionedDevices 里要有这台手机的 UDID,用
kxdevice device list查看。 - 看手机。开发者模式已打开,系统版本不低于部署目标,企业包已在「VPN 与设备管理」中信任。
- 用数据线运行
kxdevice install拿到 iOS 返回的具体原因,再对照本文对应的小节。
仍然解决不了,按排错与 FAQ末尾的方法附上 kxbuild version 和完整构建日志联系我们。