iOS 跨平台代码签名工具——Zsign
在软件开发过程中,尤其是iOS应用的发布,代码签名是至关重要的环节。今天,我要向大家推荐一个开源项目——Zsign,它是一个快速、多平台的代码签名工具,支持iOS 12+以及Linux、macOS和Windows系统。
项目介绍
当你还在烦恼如何让使用Windows系统的产品、测试进行苹果重签名打包时,还在烦恼如何突破codesign重签名局限Mac系统时,还在烦恼如何openssl签名原理复杂时,那么希望zsign签名可以帮助到你!
zsign项目地址: https://github.com/zhlynn/zsign
编译环境
本文将介绍在Linux编译使用,Windows环境可参照开源项目教程⭐️⭐️⭐️
操作系统:CentOS7
Python版本:Python3.8
部署zsign(CentOS7)
1.安装
yum install git
git clone https://github.com/zhlynn/zsign.git
cd zsign
chmod +x INSTALL.sh
./INSTALL.sh
2.编译
mkdir build
cd build
cmake ..
make
3.配置.base_profile(可选)
// 1.编辑
vim .base_profile
// 1.1 添加指定路径
export PATH
export PATH=$PATH:/zsign/build
// 2.更新
source .base_profile
// 3.验证
zsign -v
// 3.1 输出结果
version: 0.5
zsign用法
Usage: zsign [-options] [-k privkey.pem] [-m dev.prov] [-o output.ipa] file|folder
options:
-k, --pkey Path to private key or p12 file. (PEM or DER format)
-m, --prov Path to mobile provisioning profile.
-c, --cert Path to certificate file. (PEM or DER format)
-d, --debug Generate debug output files. (.zsign_debug folder)
-f, --force Force sign without cache when signing folder.
-o, --output Path to output ipa file.
-p, --password Password for private key or p12 file.
-b, --bundle_id New bundle id to change.
-n, --bundle_name New bundle name to change.
-r, --bundle_version New bundle version to change.
-e, --entitlements New entitlements to change.
-z, --zip_level Compressed level when output the ipa file. (0-9)
-l, --dylib Path to inject dylib file.
-w, --weak Inject dylib as LC_LOAD_WEAK_DYLIB.
-i, --install Install ipa file using ideviceinstaller command for test.
-q, --quiet Quiet operation.
-v, --version Show version.
-h, --help Show help.
1.显示 mach-o 和 codesignature 段信息
./zsign demo.app/execute
2.使用 p12 和 mobileprovisioning 文件对文件夹进行签名(使用缓存)。
./zsign -k dev.p12 -p 123 -m dev.prov -o output.ipa demo.app -z 9
3.更改 bundle id 和 bundle name
./zsign -k dev.p12 -p 123 -m dev.prov -o output.ipa -b 'com.tree.new.bee' -n 'TreeNewBee' demo.ipa -z 9
4.设置证书配置文件
./zsign -k dev.p12 -p 123 -m dev.prov -o output.ipa -e entitlements.plist demo.app -z 9
踩坑之旅
1.生成的ipa文件大小是原ipa文件的两倍左右。
解决:执行命令中加入-z 9来设置输出ipa文件时的压缩级别
2.使用通配符证书重签名后iOS下载文件夹报错
// 确定URL
NSString *urlStr = @"xxx";
urlStr = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *url = [NSURL URLWithString:urlStr];
// 确定request
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:0 timeoutInterval:2.0f];
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"com.example.app.backgroundSession"];
configuration.discretionary = YES;
// 确定会话
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];;
// 由会话生成任务
NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithURL:url];
[downloadTask resume];
报错信息:deny(1) file-write-unlink xxx/Library/Caches/com.apple.nsurlsessiond/Downloads/xxx*/aaa.file
原因:通配符证书重签名后的application-identifier为证书带星号的APPID,所以导致找不到指定下载路径。
解决:执行命令中加入-e entitlements.plist来改变application-identifier。
3.如何创建entitlements.plist文件
xml格式如下
<?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>xxxxxxxxxx.com.xxx.xxx</string>
<key>com.apple.developer.team-identifier</key>
<string>xxxxxxxxxx</string>
<key>get-task-allow</key>
<false/>
<key>keychain-access-groups</key>
<array>
<string>xxxxxxxxxx.com.xxx.xxx</string>
</array>
</dict>
</plist>
其中xxxxxxxxxx.com.xxx.xxx要换成ipa标识(就是证书ID+BundleID),其中xxxxxxxxxx就是你的证书ID,后面部分是bundleID
4.通过python解析获取证书ID与应用BundleID,从而创建entitlements.plist文件
import plistlib
# 检查BundleId信息
def checkBundleIdInfo(self):
infoFilePath = os.path.join(appTempPath, "Info.plist")
if os.path.exists(infoFilePath):
with open(infoFilePath, 'rb') as fp:
plist_data = plistlib.load(fp)
# 应用原ipa的bundleId,如果需要修改bundleId重签,直接使用签名的bundleId
bundleId = plist_data["CFBundleIdentifier"]
print(bundleId)
# 读取重签的证书文件
def readMobileprovision(filePath):
with open(filePath, 'rb') as f:
data = f.read()
start = data.find(b"<?xml")
end = data.find(b"</plist>") + len(b"</plist>")
plistData = data[start:end]
return data, plistlib.loads(plistData)
# 创建entitlements.plist文件
def createEntitlementsPlist(self):
data, plistData = readMobileprovision(mpPath)
entitlementsData = plistData["Entitlements"]
if "com.apple.developer.team-identifier" in entitlementsData:
# 证书ID
teamId = entitlementsData["com.apple.developer.team-identifier"]
entitlementsData["application-identifier"] = teamId + "." + bundleId
plistData["Entitlements"] = entitlementsData
# 生成entitlements.plist文件存放路径
entitlementsPath = os.path.join(tempFileDir, "entitlements.plist")
with open(self.entitlementsPath, 'wb') as f:
plistlib.dump(entitlementsData, f)
其中appTempPath是ipa解压后Payload/xxx路径,mpPath是重签名使用的xxx.mobileprovision路径
5.应用设置Product Name为中文,解压后乱码怎么处理?(python)
import zipfile
def unzipFile(sourceFile, outputPath):
"""
解压文件
:param sourceFile: 来源文件路径
:param outputPath: 输出路径
:return: 返回解压后所有文件列表
"""
zipFileList = []
with zipfile.ZipFile(sourceFile, 'r') as zip_ref:
for file_info in zip_ref.infolist():
# 解决中文文件名乱码问题
file_info.filename = file_info.filename.encode('cp437').decode('utf-8')
# print(file_info.filename)
zipFileList.append(file_info.filename)
zip_ref.extract(file_info, outputPath)
return zipFileList