授权机制 (Entitlements)
到目前为止,我们都假设所有的证书起到的作用都是一样的,并且假设如果我们有了一个有效的证书代码签名也就相应的有效。然而这当然不是唯一的规则。操作系统有许多标准来检测你的代码是否允许运行。
这些标准并不是一成不变的。举例来说,在 OS X 上一个应用是否允许被开启是由 Gatekeeper 的选项决定的,你可以在系统设置的安全选项中改变选项。在 Gatekeeper 选项中选择 “受信任的开发者或者来自 Mac App Store” 会要求被打开的应用必须被证书签名,可以是 Mac App Store 开发者的应用发布证书也可以是开发者 ID 证书。这些选项是由一个系统工具 spctl
来管理的,它管理着系统的所有安全评估策略。
在 iOS 上规则是不一样的,无论是用户还是开发者都不能改变应用开启策略,你必须有一个开发者帐号或者应用发布证书才能让应用运行在 iOS 系统上。
即使你可以让应用运行起来,在 iOS 上你的应用能做什么依然是受限制的。这些限制是沙盒管理的。沙盒和代码签名机制是不同的,这很重要。代码签名保证了这个应用里所包含的内容正如它所说的那样不多不少,而沙盒则是限制了应用访问系统的资源。这两种技术是相互合作来发挥作用的,它们都能阻止你的应用运行,也都能在 Xcode 中引起奇怪的问题。但是在日常开发过程中,沙盒可能会更经常引起问题。沙盒机制在什么时候会引起问题呢,大多数情况下都是由于一个叫做授权的机制决定的。
授权机制
授权机制决定了哪些系统资源在什么情况下允许被一个应用使用。简单的说它就是一个沙盒的配置列表,上面列出了哪些行为被允许,哪些会被拒绝。
很可能你已经猜到授权机制也是按照 plist 文件格式来列出的。Xcode 会将这个文件作为 --entitlements
参数的内容传给 codesign
,这个文件内部格式如下:
<?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>application-identifier</key>
<string>7TPNXN7G6K.ch.kollba.example</string>
<key>aps-environment</key>
<string>development</string>
<key>com.apple.developer.team-identifier</key>
<string>7TPNXN7G6K</string>
<key>com.apple.developer.ubiquity-container-identifiers</key>
<array>
<string>7TPNXN7G6K.ch.kollba.example</string>
</array>
<key>com.apple.developer.ubiquity-kvstore-identifier</key>
<string>7TPNXN7G6K.ch.kollba.example</string>
<key>com.apple.security.application-groups</key>
<array>
<string>group.ch.kollba.example</string>
</array>
<key>get-task-allow</key>
<true/>
</dict>
</plist>
在 Xcode 的 Capabilities 选项卡下选择一些选项之后,Xcode 就会生成这样一段 XML。 Xcode 会自动生成一个 .entitlements
文件,然后在需要的时候往里面添加条目。当构建整个应用时,这个文件也会提交给 codesign
作为应用所需要拥有哪些授权的参考。这些授权信息必须都在开发者中心的 App ID 中启用,并且包含在配置文件中,稍后我们会详细讨论这一点。在构建应用时需要使用的授权文件可以在 Xcode build setting 中的 code signing entitlements 中设置。
在这个应用中我启用了 iCloud 键值对存储 (key-value storage) (com.apple.developer.ubiquity-kvstore-identifier
) ,以及 iCloud 文档存储 (com.apple.developer.ubiquity-container-identifiers
)。另外我还将应用添加进了一个 App Group (比如说为了与扩展 (extensions) 共享数据,com.apple.security.application-groups
), 最后开启了推送功能 (aps-environment
)。这是一个开发版本,我会有将它连接到调试器的需求,这就需要将 get-task-allow
设为 true
。另外,app id,也就是 bundle id 加上开发者 id,也被单独列出来了。
当然你并不能随心所欲的取得授权,你的应用能否得到某一项授权是有特定的规定的。举例来说,当 get-task-allow
被设定为 ture
时,应用只能在用于开发的证书签名下运行。你被允许使用的推送环境 (aps-environment) 也存在类似的限制。
根据操作系统版本的不同我们可选的授权项目是不一样的,所以很难有一份列表可以详尽地列出所有条目。至少在文档 Adding Capabilities 中提到的所有功能都是需要经过授权的。
授权信息会被包含在应用的签名信息中。如果你在这方面遇到了问题,可以尝试查看签名信息中具体包含了什么授权信息:$ codesign -d --entitlements - Example.app
会列出一个和前面的很像的 XML 格式的属性列表。你可以将这个文件的内容添加进一个脚本,每次构建应用时用脚本检查是否包含了推送服务的授权信息,以此确保推送服务工作正常。在这里推送服务只是一个例子,你使用的服务越多,这样的时候都添加推送通知的授权,以保证可以注册推送通知。在新版本的 Xcode 6 之后,授权信息列表会以 Example.app.xcent
这样的名字的文件形式包含在应用包中。在我看来,这么做是为了在出现配置错误时提供更加有用的错误信息。
参考链接:
1.http://foggry.com/blog/2014/10/16/ios-code-signing-xue-xi-bi-ji/
2.https://objccn.io/issue-17-2/