为何要签名
对 app 进行代码签名可让用户确信它来自已知来源,且自最后一次签名之后未被修改。在您的 Mac app 或 iOS app 可以使用商店服务,安装到 iOS 设备上进行开发或测试,或者提交到 App Store 之前,必须先使用 Apple 颁布的证书对其进行签名。
在 OS X 的安全性与隐私
的设置里有一项设置是允许从以下位置下载的应用程序
,默认的设置是Mac App Store 和被认可的开发者
。
也就是说在用户不手动修改设置的情况下,用户无法打开未签名的程序。
下面就来介绍如何使用 Developer ID 为 app 签名。
注意:本文不适用于发布到 Mac App Store 的签名。
如何签名
将你的 Apple ID 添加到 Xcode
打开 Xcode 的 Preferences。
选择
Accounts
。点击左下角的加号按钮。
填入你的 Apple ID。
加入一个 Program
在添加 Apple ID 的界面,你可以选择 Join a Program...
来加入一个 program。
你也可以让 program 的管理员来将你添加到你们公司的 program。
在 Xcode 中设置 signing identity
选择你项目的 target。
选择
General
。在
Signing
中选择Developer ID
。在
Team
中选择你加入的 program。
创建 Developer ID certificate
方法一:
首先在自己的电脑上使用钥匙串访问
来创建一个certificate signing request (CSR)
。
打开
钥匙串访问
,在菜单栏中选择钥匙串访问 > 证书助理 > 从证书颁发机构请求证书
。填入你的邮件地址和常用名,选择下方的
存储到磁盘
,点击继续选择文件位置保存即可。管理员在 Member Center 里面的
Certificates, Identifiers & Profiles
页面中,选择Certificates
下方的All
。选择右上角的加号按钮。
选择
Production
下方的Developer ID
。选择证书类型
Developer ID Application
,点击Continue
。选择前面生成的 CSR(扩展名是 .certSigningRequest) 文件,点击
Continue
。选择
Generate
并且下载证书。将证书导入到 Keychain 中。
方法二:
打开 Xcode 的偏好设置,选择
Accounts
选项卡,选择加入的 program,点击View Details
。此时 Xcode 没有找到任何证书,会提示是否要帮你申请证书,此时只要选择以
The Developer ID Application
开头的选项即可。(也可以点击左边的加号来添加一个Developer ID Distribution
)等待 program 的管理员来审批。
验证:
方法一:
在 Xcode 的 Preference > Accounts
中选择加入的 program,选择 View Details...
,应该能看到一项 Developer ID Application
。
方法二:
在钥匙串访问中能找到一个名为 Developer ID Application: Your Company Name
的证书。
签名
方法一(使用 Xcode 签名):
选择菜单中的
Product > Archive
。(可选)选择
Validate...
来验证打包。点击
Export...
按照提示选择
Export a Developer ID-signed Application
。选择一个 team。
输入文件名,保存即可。
但是使用 Xcode 签名有可能会失败,下面的签名验证部分会提到。
方法二(使用命令行):
codesign --force --verbose=4 --sign "Developer ID Application: Your Company Name" Foo.app
codesign 要求项目中包含的所有框架、库都已经被签名,并且 codesign 不会自动帮你完成,这需要我们单独为每一个库进行签名后再为整个 app 签名。
签名或验证一个 framework 时使用的路径是MyCustomFramework/Versions/A
,比如
codesign -s "Developer ID Application: Your Company Name" ../MyCustomFramework/Versions/A
签名时不要使用--deep
参数。
如果 framework 签名失败,可能是由于
Info.plist 文件中的 CFBundleExecutable 值与可执行文件的文件名不一致。
目录结构不对(比如 QT),framework 的目录结构必须与下面完全一样。
MyFramework.framework/
MyFramework -> Versions/Current/MyFramework
Resources -> Versions/Current/Resources
Versions/
A/
MyFramework
Resources/
English.lproj/
InfoPlist.strings
Info.plist
Current -> A
签名验证
输入下面的命令:
spctl -a -v Foo.app
如果验证通过,则会提示:
Foo.app: accepted
source=Developer ID
origin=Developer ID Application: Your Company Name
出现下面的提示:
Foo.app: rejected
source=obsolete resource envelope
此时如果用户通过浏览器或者邮箱接收到安装包再打开 app 时就会提示文件已损坏。
解决方法:
使用下面的命令
codesign --verify --deep --verbose=3 /path/to/signed/app
找出验证不通过的重新签名,再重新签名整个 app 即可。
脚本
下面是我用来签名的脚本。
#!/usr/bin/python
import os
import commands
APP_PATH = "/path/to/Foo.app"
DEVELOPER_ID = "Developer ID Application: Your Awesome Company"
def signWithPath(path):
signCommand = "codesign --force --sign \"%s\" \"%s\"" % (DEVELOPER_ID, path)
retCode, result = commands.getstatusoutput(signCommand)
if retCode != 0:
print result
print "code sign failed"
return retCode
def validateWithPath(path):
signCommand = "codesign --verify --deep --verbose=3 \"%s\"" % path
retCode, result = commands.getstatusoutput(signCommand)
if retCode == 0:
print "Accepted!"
return 0
else:
print result
print "Rejected!"
return -2
def sign():
print "> signing frameworks & dylibs..."
if not os.path.exists(APP_PATH):
print "where's your app?!"
return
frameworkDir = os.path.join(APP_PATH, "Contents/")
# sign dylibs
for root, dirs, files in os.walk(frameworkDir):
for f in files:
if f.endswith(".dylib"):
print "signing", f
dylibPath = os.path.join(root, f)
signWithPath(dylibPath)
# sign frameworks
for root, dirs, files in os.walk(frameworkDir):
for d in dirs:
if d.endswith(".framework"):
print "signing", d
frameworkPath = os.path.join(root, d, "Versions/A")
signWithPath(frameworkPath)
print "> singing app..."
print "singing", APP_PATH
signWithPath(APP_PATH)
print "> validate code sign..."
if validateWithPath(APP_PATH) == 0:
print "Code sign completed!"
else:
print "Dohhh!"
if __name__ == '__main__':
sign()
参考
http://furbo.org/2013/10/17/code-signing-and-mavericks/
https://github.com/sunuslee/sunus-cookbook/blob/master/Cocoa/codesign.md