type
status
date
slug
summary
tags
category
icon
password
wechat_gate
notion image
iOS .entitlements 文件的作用,是声明某个 Target 希望获得哪些受代码签名保护的系统能力。但它不是一张可以自行填写的授权书。真正生效的是写入 App 可执行文件代码签名中的 Entitlements,而且必须落在 Apple 为该 App 授权的范围内。
如果只记住一句话,可以记住这个关系:
这篇文章会把 .entitlements、App ID、Provisioning Profile、Code Signing 和 iOS 运行时校验放到同一条安全链路里讲清楚,并给出一套从构建产物反查问题的方法。

iOS .entitlements 文件到底有什么作用

.entitlements 是一个 Property List 文件。它记录的是当前 Target 在构建时希望声明的特殊能力,例如:
这三个键分别对应:
  • aps-environment:使用 APNs 推送服务的环境。
  • com.apple.developer.icloud-container-identifiers:允许访问的 iCloud Container。
  • com.apple.security.application-groups:主 App 与 Extension 可共享的 App Group。
Apple 对 entitlement 的定义很明确:它是赋予可执行文件使用某项服务或技术的权利,最终以键值对形式嵌入二进制的代码签名。项目里的 .entitlements 文件只是 Xcode 计算最终结果时的一份输入。
这意味着,手动向文件里加入一个键,并不会让 App 自动获得对应能力。例如:
任何人都能写出这段 XML,但系统不会因为本地文件里有这个键,就允许 App 使用 HealthKit。它还要经过 App ID、Provisioning Profile、代码签名和系统校验。

五个角色,不是三份重复配置

Entitlements 相关问题难懂,通常不是因为 XML,而是几个相似名词承担了不同职责。
角色
它回答的问题
数据归属
.entitlements
这个 Target 想声明什么能力
本地项目
App ID Capabilities
这个 Team 名下的 Bundle ID 可以配置什么能力
Apple Developer 后台
Provisioning Profile
Apple 授权谁、哪个 App、在什么条件下运行,以及可声明哪些 Entitlements
Apple 签发
Code Signature
当前二进制实际声明了什么,并由谁签名
构建产物
iOS 与系统服务
签名、身份和权限是否有效,本次调用是否允许
设备系统
更准确的结构不是单向复制,而是本地声明与 Apple 授权在签名阶段汇合:
notion image
Apple 的 TN3125 将 Provisioning Profile 中的 Entitlements 描述为允许列表。App 真正声明某个 entitlement,则要把它放进自身代码签名。
可以把两者的关系概念化为:
但不要把它实现成简单的文本比较。Profile 可能使用通配符,签名阶段会把某些值展开成完整的 Team ID、Bundle ID 或容器标识;不同 entitlement 也可能有各自的匹配规则。排查时要理解允许关系,同时比较实际键和值,而不是只比较两段 XML 是否逐字相同。

从 Xcode 到 iOS,权限是怎样生效的

第一步:Target 声明能力

在 Xcode 中打开:
添加 iCloud、Push Notifications、App Groups 或 Associated Domains 后,Xcode 可能会:
  1. 创建或修改 .entitlements 文件。
  1. 修改 Info.plist 或链接相关 Framework。
  1. 在开发者账号中配置对应的 App ID 服务。
  1. 创建或更新 Provisioning Profile。
  1. 配置构建时使用的签名资产。
Apple 也明确提醒:并非每个 Capability 都一定对应一个 entitlement。不要根据功能名称猜键名,更不要从网络文章里复制一个看似合理的 com.apple.developer.* 键。

第二步:Apple 签发 Provisioning Profile

Provisioning Profile 不是普通 plist。它是被 Cryptographic Message Syntax 签名的数据,其中会关联:
  • App ID 或 Bundle ID 范围。
  • 可以签名的开发者证书。
  • Development 或 Ad Hoc Profile 中允许的设备。
  • 有效期和 Profile 标识。
  • Apple 授权的 Entitlements。
因为 Profile 由 Apple 加密签名,设备才能把它当成授权依据,而不是相信开发者本地任意创建的文件。

第三步:代码签名写入最终 Entitlements

构建 App 时,Xcode 会结合:
  • .entitlements 中的本地声明。
  • Apple Developer 账号信息。
  • Target 和 Build Settings。
  • 选中的 Provisioning Profile。
  • Team ID、Bundle ID 等签名上下文。
计算出最终 Entitlements,并把它们写入可执行文件的代码签名。
因此,下面三份数据可能相关,但不保证完全相同:
真正代表当前构建产物实际声明的是第三份。

第四步:系统在安装、启动和服务调用时校验

在开发、Ad Hoc 等需要 Profile 的分发场景中,设备会检查代码签名、Profile、证书、App 标识、有效期、设备范围和 Entitlements 是否满足要求。签名或权限不合法时,安装或启动会直接失败,而不是由系统静默删除超出的权限。
App 启动后,相关系统服务还会继续基于进程的签名身份实施访问控制。例如:
CloudKit 不会只相信传入的字符串。系统还会检查当前进程签名中的 iCloud entitlement,确认它是否允许访问这个容器。
这里还有一个容易被简化掉的边界:App Store 会在分发流程中检查并重新签名 App。TN3125 说明,最终从 App Store 下载的 App 不一定继续携带开发者构建时的 Provisioning Profile。所以上面的“设备比较签名与内嵌 Profile”最适合解释开发、Ad Hoc 和安装排错,不能无条件套用到所有最终分发包。

.entitlementsInfo.plist 和用户授权不是一回事

这三层经常被混在一起:
层级
典型例子
解决的问题
Info.plist
NSCameraUsageDescription
App 的元数据、运行配置,以及向用户解释为何访问隐私资源
Entitlements
iCloud、App Groups、Associated Domains
签名后的可执行文件是否具有受保护的系统能力
运行时用户授权
通知、相机、麦克风、照片
当前用户是否同意本次 App 使用相关资源
例如远程通知至少涉及两件不同的事:
  1. App 的签名需要包含有效的 aps-environment entitlement,才能使用 APNs 能力。
  1. App 要显示提醒、播放声音或更新角标,还需要通过 UNUserNotificationCenter 请求用户授权。
可以使用现代 Swift 并发接口:
Entitlement 通过,不代表用户一定同意;用户同意通知,也不能替代签名层的 APNs 配置。

常见 Entitlements 与使用场景

iCloud 和 CloudKit

它通常用于 CloudKit、iCloud Documents,以及采用 CloudKit 同步的 Core Data 或 SwiftData 场景。容器标识需要与 App ID 配置和 Profile 授权一致。

Push Notifications

发布签名下通常会得到 production。不建议通过维护两份手写值来切换环境,应让签名和 Provisioning Profile 生成正确结果,再从最终产物验证。

App Groups

它常用于主 App 与 Widget、Share Extension、Notification Service Extension 等共享容器。
主 App 和 Extension 是不同的可执行目标。两边都要配置正确的 App Group,并分别检查各自的签名 Entitlements。

Associated Domains

它可用于 Universal Links、Shared Web Credentials 等能力。签名正确只是其中一层,网站侧的关联文件和域名配置也必须正确。

Sign in with Apple

除本地 Target 外,还要确认 App ID 和服务端使用的标识配置一致。

Keychain Sharing

这里尤其要注意 App ID Prefix。历史账号、App 转移、多 Target 和多团队项目中,Prefix 不匹配可能导致安装失败或升级后无法继续访问原有 Keychain 数据。

一次理解偏差:把授权链路看成复制链

我在梳理 iCloud.ink.jinghai.markzen 这个容器配置时,最初也把关系画成了:
这个画法看起来直观,却容易让人误以为同一份配置只是复制了三遍。它还会带来一个直接的排查错误:只盯着源码中的 .entitlements,看到容器字符串存在,就认为权限已经生效。
后来把结构改成“本地声明与 Apple 授权在代码签名处汇合”,排查顺序也随之改变:
这个转变是这次梳理里最重要的教训:源码只能说明意图,产物才能说明结果。

四条命令,检查真正生效的 Entitlements

1. 查看 Target 使用哪个文件

如果项目为 Debug 和 Release 配置了不同文件,这一步可以发现当前 Configuration 实际引用哪一个路径。

2. 查看 App 代码签名中的最终 Entitlements

部分较新的 codesign 版本也接受:
codesign 的诊断信息可能写到标准错误流。在脚本里需要捕获输出时,可以显式合并:

3. 解码内嵌 Provisioning Profile

4. 只提取 Profile 的 Entitlements

最终应该比较的是:
notion image
如果你只检查项目文件,会漏掉这些问题:
  • Build Setting 指向了另一份 .entitlements
  • Debug 与 Release 使用了不同配置。
  • Archive 选择了不同的 Team 或 Profile。
  • Profile 没有在 App ID 能力变更后更新。
  • 通配符在签名时展开成了不符合预期的值。
  • 主 App 正确,但 Extension 的签名配置错误。

invalid entitlements 应该怎样定位

构建时报 Profile 不包含某个 entitlement

常见信息类似:
按这个顺序检查:
  1. 该 entitlement 是否真实存在,当前平台和账号是否有资格使用。
  1. Xcode 的 Signing & Capabilities 是否已添加对应能力。
  1. Apple Developer 后台的 App ID 是否启用了对应服务。
  1. App ID 或证书变更后,Profile 是否重新生成。
  1. 当前 Configuration 是否选中了更新后的 Profile。
如果它属于 Apple 审批的 Managed Capability,还要先确认账号已经获得授权。仅在本地写键无法绕过审批。

安装或启动时报签名权限无效

常见信息包括:
或:
这时不要先删除 DerivedData 反复重试。优先导出 codesign 与 Profile 的 Entitlements,核对:
  • application-identifier
  • Team Identifier 与 App ID Prefix
  • Bundle ID
  • App Group
  • iCloud Container
  • Keychain Access Groups
  • get-task-allow
  • aps-environment
清缓存只能解决本地选择了旧资产一类问题,不能修复 App ID 或 Profile 本身没有授权。

安装成功,但系统服务仍然拒绝

这种情况说明问题可能已经从“签名能否通过”进入“服务配置是否完整”:
  • CloudKit Container 是否属于当前 Team。
  • 容器环境和 Schema 是否已经正确配置。
  • Associated Domains 的网站文件是否可访问且内容匹配。
  • App Group 是否同时配置在主 App 与相关 Extension。
  • 通知是否同时完成 APNs 能力和用户授权。
Entitlements 是必要条件,但不保证服务端配置、用户授权和业务代码也正确。

实际项目中的七条建议

  1. 优先通过 Signing & Capabilities 添加能力。除非官方文档要求,不要凭键名手写。
  1. .entitlements 提交到 Git。它是项目配置的一部分,但不要复制其他项目的 Team、App Group 或 iCloud Container。
  1. 每个可执行 Target 分开检查。App、Widget、Share Extension 都有自己的签名和权限边界。
  1. 区分 Debug、Release 和 Archive。真机开发包能用,不代表发布包的 Entitlements 一定相同。
  1. App ID、证书或能力变化后更新 Profile。手动签名项目尤其要注意旧 Profile。
  1. 把 Archive 产物当成最终证据。提交前检查实际签名,不要只看 Xcode UI 是否显示绿色。
  1. Simulator 不能替代真机签名验证。Apple 的 TN2415 指出,Simulator 构建不经过与设备构建相同的代码签名流程。

总结

.entitlements 最容易被误解成“权限配置文件”,但更准确的说法是“代码签名权限的项目级声明输入”。
完整链路是:
遇到问题时,不要止步于“文件里已经写了”。从 codesign 输出和 Profile 的 Entitlements 开始比较,通常能更快找到真正不一致的那一层。

参考资料

 
2026.07.29 18:15 沪 · 赵巷
📌 声明:本文由 AI 辅助完成