对 app 进行代码签名可让用户确信它来自已知来源,且自最后一次签名之后未被修改。在您的 Mac app 或 iOS app 可以使用商店服务,安装到 iOS 设备上进行开发或测试,或者提交到 App Store 之前,必须先使用 Apple 颁布的证书对其进行签名。
在 OS X 的 安全性与隐私
的设置里有一项设置是 允许从以下位置下载的应用程序
,默认的设置是 Mac App Store 和被认可的开发者
。
也就是说在用户不手动修改设置的情况下,用户无法打开未签名的程序。
下面就来介绍如何使用 Developer ID 为 app 签名。
注意:本文不适用于发布到 Mac App Store 的签名。
Accounts
。 在添加 Apple ID 的界面,你可以选择 Join a Program...
来加入一个 program。
你也可以让 program 的管理员来将你添加到你们公司的 program。
General
。 Signing
中选择 Developer ID
。 Team
中选择你加入的 program。 方法一:
首先在自己的电脑上使用 钥匙串访问
来创建一个 certificate signing request (CSR)
。
钥匙串访问
,在菜单栏中选择 钥匙串访问 > 证书助理 > 从证书颁发机构请求证书
。 存储到磁盘
,点击继续选择文件位置保存即可。 Certificates, Identifiers & Profiles
页面中,选择 Certificates
下方的 All
。 Production
下方的 Developer ID
。 Developer ID Application
,点击 Continue
。 Continue
。 Generate
并且下载证书。 方法二:
Accounts
选项卡,选择加入的 program,点击 View Details
。 The Developer ID Application
开头的选项即可。(也可以点击左边的加号来添加一个 Developer ID Distribution
) 验证:
方法一:
在 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
。 但是使用 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 签名失败,可能是由于
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()
https://developer.apple.com/library/mac/documentation/IDEs/Conceptual/AppDistributionGuide/MaintainingCertificates/MaintainingCertificates.html#//apple_ref/doc/uid/TP40012582-CH31-SW30
http://furbo.org/2013/10/17/code-signing-and-mavericks/
https://github.com/sunuslee/sunus-cookbook/blob/master/Cocoa/codesign.md