我们知道一个iOS项目发布的完整流程是
Build->签名->打包ipa->上传AppStore
今天我们就来研究签名这个过程,并用脚本实现重签名。
重签名一般用来分发应用,比如我们前面上传蒲公英的脚本,在打包ipa之前,用企业证书进行重新签名,这样上传到蒲公英的ipa包所有人都能安装,没有设备闲置
另外一种用途就是破解别人的App,然后重新打包签名。
准备文件
App文件
一般来说,只要App文件就可以,不过一般我们可以从下面的途径获得
- 用xcode编译产生的App,或者用命令
xcodebuild
的到的app文件 - 从AppStore下载,解压安装包得到的App文件
- 越狱渠道下载ipa,解包得到App文件
Bundlle Id
这个不用多说,没有bundleId 一切免谈
mobileprovision 配置文件
同样不必多说,必须与bundleId对应,如果是development,必须包含测试设备才能安装
证书
开发证书提前安装到钥匙串,我们后面使用的时候直接使用其名称
entitlements.plist
授权文件,签名时必须要指定的配置文件,如果不指定这个文件,那么签名后的文件无法安装,格式如下,不包括所有的属性
1 | "1.0" encoding="UTF-8" xml version= |
不同环境的签名,entitlements.plist里面的属性也是略有不同,比如distribute签名get-task-allow
属性为false,并且新增了属性beta-reports-active 为true
,aps-environment
属性为production
那么这样一个文件,难道需要我们每次签名的时候,手动创建,并且修改里面这一堆属性吗,答案显然是否定的。其实整个entitlements信息已经包含在我们打包的mobileprovision 配置文件里面了。我们通过如下命令打印mobileprovision的信息到终端
1 | security cms -D -i xxxxx.mobileprovision |
输出内容为plist文件格式,其中包含entitlements字段,对应的内容就是我们上面entitlements.plist需要的内容
1 | ......... |
所以我们只需要导出Entitlements字段的内容为一个plist文件即可,这就用到了/usr/libexec/PlistBuddy
命令,如下组合命令在当前目录生成一个entitlements.plist文件
1 | /usr/libexec/PlistBuddy -x -c "print :Entitlements " /dev/stdin <<< $(security cms -D -i $APP_PATH/embedded.mobileprovision) > entitlements.plist |
至此,签名所需要的内容都准备齐全,接下来进入签名流程
签名流程
替换embedded.mobileprovision
App会将mobileprovision配置文件打包进bundle,并以embedded.mobileprovision命名,我们要做的第一步就是用我们自己的mobileprovision,替换App内部的embedded.mobileprovision
1 | cp $PROVISION_PATH $APP_PATH/embedded.mobileprovision |
生成entitlements.plist
用我们准备的mobileprovision配置文件来生成授权文件entitlements.plist,由于我们第一步已经将我们准备的mobileprovision文件拷贝进App文件夹内,并重命名为embedded.mobileprovision,所以这里直接对embedded.mobileprovision解析生成entitlements.plist
1 | /usr/libexec/PlistBuddy -x -c "print :Entitlements " /dev/stdin <<< $(security cms -D -i $APP_PATH/embedded.mobileprovision) > entitlements.plist |
修改BundleId
App内部会包含一个info.plist文件,其实就是我们开发时的工程info配置文件。
1 | /usr/libexec/PlistBuddy -c 'Set :CFBundleIdentifier $NEW_BUNDLE_ID' $APP_PATH/info.plist |
重新签名
签名命令
1 | codesign -f -s "$CER_NAME" --entitlements entitlements.plist $APP_PATH |
如上即完成了整个签名流程,打开pp助手,将安装包丢进去,即可成功安装到手机。
过程分析
_CodeSignature
App签名过程中最重要的两个文件
- _CodeSignature 文件夹
- embedded.mobileprovision
_CodeSignature文件夹在App顶层目录,打开_CodeSignature看到CodeResources文件,用文本编辑器打开,发现其是一个plist文件,保存了App目录里面所有文件的签名(包括embedded.mobileprovision,info.plist)
1 | "1.0" encoding="UTF-8" xml version= |
当我们替换embedded.mobileprovision,修改info.plist之后,再调用codesign命令的时候 重新生成了_CodeSignature。
iOS系统启动App的时候会检查_CodeSignature,以确保包的资源是没有被篡改过的。
entitlements.plist
这个授权文件其实已经包含在embedded.mobileprovision文件里面了,按照逻辑来讲,不用提供也可以,但是实际测试,还是必须要提供,不然签名后的App无法安装。
观察xcode的build或者archive的log信息
发现无论是build还是archive,xcode在签名的时候都指定了entitlements文件,我们可以复制这里的xxx.xcent路径然后,从finder中寻找打开,可以发现其内容与我们上面介绍的entitlements.plist内容是一致的。
所以我这里的签名流程果断跟xcode一致,使用entitlements.plist