✍️ CI环境完成IPA签名

昨天准备给CI里面添加重签名IPA的命令,后来觉的这个功能加载Makefile里面比较合适,就在Makefile文件里面添加了一个sign的target. 证书📄用的是之前海鲜🦞市场购入的10元一张的开发者证书。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
BUILD_DIR=$(PWD)/Build
PROJECTS=$(wildcard *.xcodeproj)
KEYCHAIN_PATH=$(BUILD_DIR)/temp.keychain
KEYCHAIN_PASSWORD="xxxxxxxxx"
KEYCHAIN_ACCOUNT="iPhone Developer: ******** (xxxxxxxxxx)"

all: build ipa

build:
mkdir -p "$(BUILD_DIR)"
xcodebuild clean \
-configuration Release \
-scheme App \
-workspace App.xcworkspace | xcpretty
xcodebuild archive \
-archivePath "$(BUILD_DIR)"/App \
-configuration Release \
-scheme App \
-workspace App.xcworkspace \
-allowProvisioningUpdates \
CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO | xcpretty


ipa: build sign
mkdir -p "$(BUILD_DIR)"/Release
mkdir -p "$(BUILD_DIR)"/Release/Payload
cp -r "$(BUILD_DIR)"/App.xcarchive/Products/Applications/App.app "$(BUILD_DIR)"/Release/Payload
cd "$(BUILD_DIR)"/Release && zip -r App.ipa Payload

sign:
@echo "✍️ Signing..."
security create-keychain -p $(KEYCHAIN_PASSWORD) $(KEYCHAIN_PATH)
security unlock-keychain -p $(KEYCHAIN_PASSWORD) $(KEYCHAIN_PATH)
security import Script/iOS.p12 -k $(KEYCHAIN_PATH) -P $(KEYCHAIN_PASSWORD) -T /usr/bin/codesign
security import Script/AppleWWDRCAG3.cer -k $(KEYCHAIN_PATH) -P $(KEYCHAIN_PASSWORD) -T /usr/bin/codesign
security cms -D -i Script/iOS.mobileprovision > Build/entitlement_full.plist
/usr/libexec/PlistBuddy -x -c 'Print:Entitlements' Build/entitlement_full.plist > Build/entitlement.plist
cp Script/iOS.mobileprovision "$(BUILD_DIR)"/App.xcarchive/Products/Applications/App.app/embedded.mobileprovision
security set-keychain-settings $(KEYCHAIN_PATH)
security default-keychain -s $(KEYCHAIN_PATH)
security find-identity -p codesigning $(KEYCHAIN_PATH)
find "$(BUILD_DIR)"/App.xcarchive/Products/Applications/App.app -name '*.framework' -type d | while read -r framework; do \
codesign -s $(KEYCHAIN_ACCOUNT) --keychain $(KEYCHAIN_PATH) --entitlements Build/entitlement.plist -f "$$framework"; \
done
codesign -s $(KEYCHAIN_ACCOUNT) --keychain $(KEYCHAIN_PATH) --entitlements Build/entitlement.plist -f "$(BUILD_DIR)"/App.xcarchive/Products/Applications/App.app
codesign -vvv --verify --deep --strict "$(BUILD_DIR)"/App.xcarchive/Products/Applications/App.app
security delete-keychain $(KEYCHAIN_PATH)

clean:
rm -rf $(BUILD_DIR)

由于是CI环境里面,所以创建了一个临时的keychain,在这个临时的keychain里面导入了开发者证书和苹果的根证书。

这里也遇到几个问题🙋,简单记录一下:

  • 编译签名成功,隔空投送到手机,提示无法验证完整性

这个由于之前没有对Framework下面的framework签名,所以在Makefile里面添加了下面👇这一段

1
2
3
find "$(BUILD_DIR)"/App.xcarchive/Products/Applications/App.app -name '*.framework' -type d | while read -r framework; do \
codesign -s $(KEYCHAIN_ACCOUNT) --keychain $(KEYCHAIN_PATH) --entitlements Build/entitlement.plist -f "$$framework"; \
done
  • 笔记本上面签名成功,到CI环境签名报错,提示error: The specified item could not be found in the keychain.

这里签名的时候需要指定keychain

1
codesign -s $(KEYCHAIN_ACCOUNT) --keychain $(KEYCHAIN_PATH) --entitlements Build/entitlement.plist -f "$(BUILD_DIR)"/App.xcarchive/Products/Applications/App.app

如果还是没有效果,修改默认的keychain,反正在CI环境也没什么关系

1
security default-keychain -s $(KEYCHAIN_PATH)
  • 签名提示Warning: unable to build chain to self-signed root for signer

这个问题的查看证书的组织,比如这个证书

证书不被信任

双击证书,查看签发者组织

签发者组织

可以看到👀,签发组织是Apple Worldwide Developer Relations Certification AuthorityG3

在苹果的证书下载网站

导入根证书
下载合适的证书后导入,在CI环境可以用命令:

1
security import Script/AppleWWDRCAG3.cer -k $(KEYCHAIN_PATH) -P $(KEYCHAIN_PASSWORD) -T /usr/bin/codesign

签名遇到的问题大致就这么多。

快捷安装IPA

IPA签好名,快捷安装的方法有几种:

  • 隔空投送IPA可以直接安装
  • 用safari下载IPA也会直接安装
  • 扫码安装(itms-services,二维码内容)
  • 点击连接安装(itms-services,网页重定向)

直接下载IPA的方式没有什么特别的,缺点就是在下载过程,会显示缺省的图标,用后两种方式下载,可以在清单文件里面指定一个图标显示

1
itms-services://?action=download-manifest&url=$plist_url

其中$plist_url就是清单文件的内容。这里提供一个模版

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<?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>items</key>
<array>
<dict>
<key>assets</key>
<array>
<dict>
<key>kind</key>
<string>software-package</string>
<key>url</key>
<string>new_software_package_url</string>
</dict>
<dict>
<key>kind</key>
<string>display-image</string>
<key>url</key>
<string>new_display_image_url</string>
</dict>
<dict>
<key>kind</key>
<string>full-size-image</string>
<key>url</key>
<string>new_full_size_image_url</string>
</dict>
</array>
<key>metadata</key>
<dict>
<key>bundle-identifier</key>
<string>top.ourfor.app.App</string>
<key>bundle-version</key>
<string>1</string>
<key>kind</key>
<string>software</string>
<key>title</key>
<string>AIApp</string>
</dict>
</dict>
</array>
</dict>
</plist>

里面的内容可以在CI编译后,通过python脚本修改