先把五个容易混淆的位置列在同一张表

排查签名时,单独确认“Bundle ID 看起来正确”通常不够。至少要并排记录五处信息:Xcode target 的 Bundle Identifier、Apple Developer 中注册的 App ID、该 App ID 允许的 capabilities、用于签名的 provisioning profile,以及最终归档中签名与嵌入 profile 的 entitlements。它们代表不同阶段,名称相近但作用并不相同。

建议以最终归档为核对对象,并写下构建配置、团队、签名方式和 profile 标识。开发构建能够运行,只能说明开发配置曾经满足要求;分发归档可能选用不同的 profile,entitlements 也会在分发阶段重新应用,因此仍需单独检查。

  • 同时记录 target、App ID、capabilities、profile 与归档 entitlements。
  • 开发构建和分发归档分开验证。

核对 target Bundle Identifier 与显式 App ID

Apple 把 App ID 定义为 provisioning profile 中用于标识 App 的两段式字符串。对于单个 App,通常使用显式 App ID;注册时填写的 Bundle ID 应与 Xcode target Summary 中的 Bundle ID 匹配。检查时不要只看产品名称,要逐字符比较大小写、点号、后缀以及构建配置替换后的最终值。

如果项目通过 xcconfig、环境变量或不同 scheme 生成多个 Bundle ID,应分别记录 Debug、Release 和各分发变体的展开结果。App Extension、Widget 或 App Clip 等附属 target 也有自己的 Bundle ID 和签名配置,不能只核对主 App。

  • 比较 Xcode 展开后的 Bundle Identifier 与已注册显式 App ID。
  • 为主 App 和每个附属 target 分别建行检查。

把 App ID capabilities 当作允许范围核对

Apple 说明,App ID 上启用的 capabilities 构成该 App 可使用能力的允许列表。先在 Certificates, Identifiers & Profiles 中打开目标 App ID,记录当前允许的能力,再与 Xcode target 的 Signing & Capabilities 页面比较。某项能力只在网站上开启、却没有加入 target,或者只在 target 中声明、却未被 App ID 允许,都值得进一步检查。

不同平台、会员资格和 App ID 类型支持的能力并不完全相同。若 capability 复选框不可用,不应通过手写 entitlement 猜测绕过,而应核对该能力是否要求显式 App ID、额外申请或特定配置。把“允许使用”与“已经完成配置”分开记录,可以减少误判。

  • 逐项对照 App ID 允许的 capabilities 与 target 实际启用项。
  • 记录因平台、账号或 App ID 类型而不可用的项目。

检查需要额外标识符或容器的能力

部分 capabilities 不只是一个开关。Apple 在启用能力的说明中列出 Sign in with Apple、App Groups、Apple Pay、Data Protection、iCloud 和 Push Notifications 等需要额外步骤的项目。例如 App Groups 要把具体 group 分配给 App ID,iCloud 要选择容器,Apple Pay 要关联 Merchant ID。

这类能力应把关联对象也纳入清单:App Group 标识符、iCloud container、Merchant ID、主 App ID 分组关系,以及扩展 target 是否使用同一组配置。核对重点是 Apple Developer 后台、Xcode target 与最终 entitlement 值是否指向同一对象,而不是仅确认 capability 名称存在。

  • 为每个 capability 记录对应 group、container 或其他标识符。
  • 主 App 与扩展之间的共享能力要核对相同关联对象。

Capabilities 变更后重新生成受影响的 profile

在 App ID 上启用或停用 capability 后,旧 provisioning profile 不会自动变成包含新配置的可用文件。Apple 明确说明,包含已修改 App ID 的 profiles 会变为无效,需要重新生成。完成后台变更后,应打开相关 profile,生成新版本,并确认 Xcode 或构建系统实际取得新文件。

手动签名时,可以记录 profile 的名称、UUID、到期日和关联证书;自动签名时,则确认 Xcode 请求到满足当前 Bundle ID、entitlements、设备与证书配置的 profile。若本机仍缓存旧文件,可能出现工程界面已经更新、归档却继续使用旧 profile 的情况,因此要以归档结果为准。

  • App ID capabilities 变更后重新生成所有相关 profiles。
  • 检查归档使用的 profile 标识,避免被本地旧缓存误导。

比较签名 entitlements 与嵌入描述文件

Apple 的 TN2415 说明,代码签名过程中,Xcode 会依据选中的 provisioning profile 和 entitlement 文件把能力写入 App 签名,同时将 profile 嵌入 App bundle。系统在安装或启动时会验证这些 entitlements,并检查签名与嵌入 profile 是否匹配。若存在意外或配置错误的 entitlement,可能出现安装或启动错误。

因此检查应分两份输出:一份来自 .app 签名,一份来自 embedded.mobileprovision。重点比较 application-identifier、team-identifier、keychain-access-groups 以及项目实际使用能力对应的键。不要为了“补齐”差异而随意手写 entitlement;先回到 target capability、App ID 和 profile 生成条件查找来源。

  • 分别查看 App 签名和 embedded.mobileprovision 中的 entitlements。
  • 对差异追溯到 target、App ID 或 profile,而不是直接补写未知键。

特别检查 application-identifier 的前缀与 Bundle ID

TN2415 将 application-identifier 描述为“前缀.Bundle ID”的形式。签名中的值会包含完整 Bundle ID;profile 关联通配符 App ID 时可能在 profile 中看到星号。系统还会比较 App 签名和嵌入 profile 中 application-identifier 的前缀,前缀不匹配会阻止安装或启动。

遇到迁移团队、历史 App ID prefix、重签名或多个开发者团队参与交付时,应把 Team ID 与 App ID prefix 分开记录,不要假设二者在所有历史项目里必然相同。处理方式通常是用前缀匹配的 profile 重新构建,并保证所有代码签名阶段选择一致的团队和配置。

  • 拆分比较 application-identifier 的 prefix 与完整 Bundle ID。
  • 团队迁移或历史项目要单独确认 App ID prefix。

归档与提交前完成最后一轮一致性检查

在 Xcode Organizer 中进入分发流程时,Apple 建议查看分发构建的 entitlements 摘要,这是提交前确认能力是否符合预期的机会。若需要更细的证据,也可以对导出的 .app 使用 codesign 查看签名 entitlements,并用 security 解码 embedded.mobileprovision,再把结果与本次发布清单一起保存。

最后逐项确认:Release Bundle ID 对应正确显式 App ID;target capabilities 已在 App ID 允许范围内;额外容器或 group 关联一致;相关 profile 状态有效且在变更后重新生成;证书和团队正确;签名与嵌入 profile 的关键 entitlements 匹配。若其中一项无法确认,先暂停交付并回到对应层修正。

  • 保存分发构建的 entitlement 摘要与 profile 标识。
  • 按 Bundle ID、capabilities、关联对象、profile、证书和签名顺序复核。