目的
在新開發的編譯環境,使用 match 自動下載最新憑證與 profile,或是在每次編譯時候更新最新的 profile。
版本
本文 fastlane version : 2.171.0
Match 包含 sigh and cert
- sigh 操作 profile
- cert 操作 certificate
Matchfile
初始化
1
| bundle exec fastlane match init
|
跟目錄會出現一個 Matchfile,修改一下內容。
1
2
3
4
5
6
7
| git_url("git@bitbucket.org:git_repo_user_name/your_ios_cert.git")
storage_mode("git")
git_full_name("git.user.name")
git_user_email("git.user.email")
verbose(true)
git_branch("master")
app_identifier(["tools.fastlane.app", "tools.fastlane.app2"])
|
執行:
之後可直接在 CLI 執行
1
| bundle exec fastlane match
|
就會自動產生憑證與 profile 並且上傳到 git 之中。
第一次執行過程時,會多次要求輸入一些東西:
- 開發者帳號密碼
- 開發者帳號兩次驗證的驗證碼
- 將憑證與 profile 加密的密碼
上述輸入過的密碼都會儲存在 keychain 的密碼中。
Fastfile 範例
也可以在 lane 之中執行 match,並且加入個別條件的參數。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| platform :ios do
lane :beta do
match(
git_branch: "master",
app_identifier: "tools.fastlane.app",
type: "adhoc",
profile_name: "ProfileName",
)
build_ios_app(
...
)
end
end
|
type: development/adhoc/appstore
或是手建立一個 lane 只 readonly 下載所有 profile
1
2
3
4
5
| lane :match_all do
sh "fastlane match development --readonly"
sh "fastlane match adhoc --readonly"
sh "fastlane match appstore --readonly"
end
|
將所有 profile 更新到最新,並安裝至內部 ~/Library/MobileDevice/Provisioning Profiles/.....
,後上傳至 git
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
| platform :ios do
desc "Description of what the lane does"
lane :match_all do
match(
type: "appstore",
api_key: your_api_key()
)
match(
type: "adhoc",
api_key: your_api_key()
)
match(
type: "development",
api_key: your_api_key()
)
end
def your_api_key()
api_key = app_store_connect_api_key(
key_id: "6XXXXXXXXX",
issuer_id: "4xxxxxxx-1xxx-43e4-axxx-xxxxxxxx474b",
key_filepath: "~/fastlanefiles/[FastlaneUploadAppManagerKey01][ISSUE_ID][4xxxxxxx-1xxx-43e4-axxx-xxxxxxxx474b][KEY_ID][6XXXXXXXXX].p8",
duration: 1200, # optional (maximum 1200)
in_house: false # optional but may be required if using match/sigh
)
return api_key
end
end
|
其他詳細參數使用方式可參考文件
https://docs.fastlane.tools/actions/match/#parameters
Git 目錄結構
match 會在 git 上依照此目錄結構放置檔案。
- certs
- development
- Development 的 Cert id.cer
- Development 的 Cert id.p12
- distribution
- Distribution 的 Cert id.cer
- Distribution 的 Cert id.p12
- profiles
- development
- Development_your.app.bundle.id.mobileprovision
- adhoc
- AppStore_your.app.bundle.id.mobileprovision
- appstore
- AdHoc_your.app.bundle.id.mobileprovision
Git 注意事項
- match 會抓取憑證資料夾的最後一個 .cer 與 .p12 如果塞了多個憑證可能會拿到錯的憑證。
- 如果你的 Certs 跟 profiles 打算手動產生,目錄結構與檔案名稱一定要按照此格式,在
非readonly
模式下,match 會自動產生新的 Cert 與 profiles,就算你已經原本有 Cert 了,如果 Cert 已經有兩個會創建失敗。 - AppID 要在開發者後台的 Identifiers 先建好,match 才能建立 cert 成功。
- Profiles 在建立時,預設是全選 devices。
- profile 名稱可以用 match 的 profile_name 修改預設名稱,預設是
match AdHoc/Development/AppStore your.bundle.id
手動管理憑證與 Profile
如果你的專案已經上線一段時間,重做憑證可能不太適合,這時可以用手動管理方式將憑證放置 git repo 中,但是須按照 上述的目錄規則,並且將檔案加密。
網路上有些教學加密方式與現在的版本不同,我是用參考文件(Sync Code Signing:Manual Decrypt)的手動解密方式去反過來加密,目前版本結果是可以正常加密解密成功。
match 會將 public key 的 cer 檔與 private key 的 p12 檔放置 Git Repo 中,以下為加密解密並且產生檔案的方式。
加密
首先從 kaychain export 包含 private key 的 cert.p12 檔案
Cer 檔案
1
2
3
4
5
6
7
8
| # 從 cert.p12 分離出 Public Certificates 的 pem
openssl pkcs12 -clcerts -nokeys -in cert.p12 -out publicCert.pem
# 轉成 der
openssl x509 -outform der -in publicCert.pem -out publicCert.der
# 轉成 cer
openssl aes-256-cbc -k "<password>" -in publicCert.der -out cert_id.cer -a -e -md md5
|
p12 檔案
從 keychain export 憑證的 private key,不包含憑證本身的 private_key.p12 檔案
1
2
3
4
5
| # 從 cert.p12 分離出 Private Key 的 pem
openssl pkcs12 -nocerts -nodes -in cert.p12 -out private_key.pem
# 轉成 p12 並加密碼
openssl aes-256-cbc -k "<password>" -in private_key.pem -out cert_id.p12 -a -e -md md5
|
cert_id 查詢方式可用 ruby 的腳本
解密
Cer 檔案
提取 Repo 的 certs/<type>/cert_id.cer
1
2
3
4
5
| # 轉成 der
openssl aes-256-cbc -k "<password>" -in cert_id.cer -out cert.der -a -d -md md5
#轉成 pem
openssl x509 -inform der -in cert.der -out cert.pem
|
p12 檔案
提取 Repo 的 certs/<type>/cert_id.p12
1
2
| # 轉成 pem
openssl aes-256-cbc -k "<password>" -in cert_id.p12 -out private_key.pem -a -d -md md5
|
合成 private_key.pem 與 cert.pem
1
2
| openssl pkcs12 -export -out "cert.p12" -inkey "private_key.pem" -in "cert.pem" -password pass:<password>
# password 是 p12 匯入時候要輸入的密碼
|
會做成一個包含 private_key 與憑證 的 p12 檔案,就可以匯入 keychain
加解密 provisioning
Provisioning Profile 的加密方式也是用 openssl aes-256-cbc 方式
1
2
| openssl aes-256-cbc -k "<password>" -in input.mobileprovision -out AdHoc_xxxxx.mobileprovision -a -d -md md5
# 加密 -e / 解密 -d
|
建立成 bash script
我這邊建立成 script 的方式,方便操作。
https://gist.github.com/pokeduck/bc4fc18f93d0e322f5bf229d6464f6be
Cert ID 的取得方式
- 取得 cert id 的方式,這邊的 cert id 不是 team id ,在 Fastlane 內有 spaceship 的 Ruby Library 可以取得所有 Cert id。
1
2
3
4
5
6
7
8
9
10
| #cert.rb
require 'spaceship'
Spaceship.login('your_developer_account@email.com') #開發者者帳號
Spaceship.select_team
Spaceship.certificate.all.each do |cert|
cert_type = Spaceship::Portal::Certificate::CERTIFICATE_TYPE_IDS[cert.type_display_id].to_s.split("::")[-1]
puts "Cert id: #{cert.id}, name: #{cert.name}, expires: #{cert.expires.strftime("%Y-%m-%d")}, type: #{cert_type}"
end
|
然後執行 ruby cert.rb
就會列出該帳號底下所有已建立的
1
2
3
4
| Cert id: XXX0000XXX, name: Development, expires: 20xx-xx-xx, type: AppleDevelopment
Cert id: XXX0000XXX, name: Distribution, expires: 20xx-xx-xx, type: AppleDistribution
Cert id: XXX0000XXX, name: APNs Development iOS, expires: 20xx-xx-xx, type: DevelopmentPush
...
|
在 Keychain 的密碼
開發者帳號
可以預先用 fastlane tool 在 keychain 新增開發者帳號密碼
1
2
3
4
5
| # 新增Apple帳號密碼至keychain
fastlane fastlane-credentials add --username your.apple.dev.id@domain.com
# 刪除帳號密碼
fastlane fastlane-credentials remove --username your.apple.dev.id@domain.com
|
參考來源: https://github.com/fastlane/fastlane/tree/master/credentials_manager
執行成功後會在鑰匙圈存取 > 登入 > 密碼中,新增一組名為 deliver.your.apple.dev.id@domain.com
的資料。
憑證密碼
當 match 執行到無法解密的憑證時會在輸入框提示密碼
1
2
3
4
5
6
7
8
| [16:51:44]: Cloning remote git repo...
[16:51:44]: If cloning the repo takes too long, you can use the `clone_branch_directly` option in match.
[16:51:46]: Checking out branch master...
[16:51:46]: Enter the passphrase that should be used to encrypt/decrypt your certificates
[16:51:46]: This passphrase is specific per repository and will be stored in your local keychain
[16:51:46]: Make sure to remember the password, as you'll need it when you run match on a different machine
/Users/your_name/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/highline-1.7.10/lib/highline.rb:624: warning: Using the last argument as keyword parameters is deprecated
[16:51:46]: Passphrase for Match storage:
|
解碼成功後會在鑰匙圈建立密碼,名稱:match_git@bitbucket.org:your_repo/your_cert_repo.git
參考
openssl
match