cert、sigh和match
是Fastlane中的三個Tool,他們都是與證書相關的工具。cert
的做用是獲取簽名證書或刪除過時的證書;sigh
的做用是管理配置文件(provisioning profile),好比建立新的、修復過時的、刪除本地的等;match
的主要做用是使用cert
和sigh
建立新的證書和配置文件,並它們放置在git上,而後重複使用。ios
cert
這個Tool下定義了兩個Command,分別是create
和revoke_expired
,其中create
是默認Command。 能夠經過在終端中執行下列命令調用git
#調用create
fastlane cert
fastlane cert create
#調用revoke_expired
fastlane cert revoke_expired
複製代碼
除了在終端使用,cert
還能夠在lane中被當作action來調用,這也是使用最頻繁的調用方式。 當cert
被當作action被調用時,其效果和在終端調用fastlane cert [create]
的效果是同樣的。json
cert
中的create
的做用是獲取簽名證書和其私鑰,而後將簽名證書和其私鑰(p12)導入到鑰匙鏈中。 爲了獲取證書,首先它會去檢測本地是否存在它想要的證書,若是沒有則它會去你的AppleID帳號中嘗試建立一個新的。數組
本文只討論create
這個Command,下文中若是沒有特殊說明,指的都是這種狀況。 當在終端執行fastlane cert
時,其執行邏輯以下 xcode
建立:output_path
指向的目錄bash
獲取AppleID 可經過:username
、環境變量CERT_USERNAME、DELIVER_USER、DELIVER_USERNAME
或Appfile
三種途徑獲取;若是沒有,則在終端請求用戶輸入AppleID。併發
獲取AppleID對應密碼 可經過環境變量FASTLANE_PASSWORD
和DELIVER_PASSWORD
設置;若是沒有,則在終端使用security find-internet-password -g -s deliver.#{AppleID}
查看鑰匙鏈中是否存儲了對應密碼,其中AppleID是[步驟2]中獲取的;若是沒有,則在終端請求用戶輸入,而且會將用戶輸入的密碼存儲在鑰匙鏈中。app
登陸到蘋果開發網站 若是有兩步驗證,則還須要輸入對應手機的驗證碼ide
獲取TeamID 若是這個AppleID帳號加入了多個Team,能夠經過設置TeamID或TeamName來指定一個Team,具體來講能夠經過環境變量FASTLANE_TEAM_ID
、CERT_TEAM_ID
或:team_id
指定TeamID,經過環境變量FASTLANE_TEAM_NAME
,CERT_TEAM_NAME
或:team_name
指定TeamName,不然,須要用戶手動來選擇。若是你的AppleID帳號只加入了一個Team,則直接使用此Team的TeamID。工具
檢測force 6.1. 當:force
爲true
時,強制建立證書,執行[步驟8] 6.2. 當:force
爲false
時,執行[步驟7]
檢測本地證書 遍歷AppleID帳號中的已建立證書,檢測此證書是否存在於鑰匙鏈中,或者:output_path
目錄下是否存在此證書對應的密鑰(p12),其具體的檢測流程會在下文中講到。 7.1. 本地有可用證書,執行[步驟9] 7.2. 本地無可用證書,執行[步驟8]
建立新證書 首先生成CSR文件和RSA密鑰對
def create_certificate_signing_request
key = OpenSSL::PKey::RSA.new(2048)
csr = OpenSSL::X509::Request.new
csr.version = 0
csr.subject = OpenSSL::X509::Name.new([
['CN', 'PEM', OpenSSL::ASN1::UTF8STRING]
])
csr.public_key = key.public_key
csr.sign(key, OpenSSL::Digest::SHA1.new)
return [csr, key]
end
複製代碼
而後生成請求
r = request(:post, "account/#{platform_slug(mac)}/certificate/submitCertificateRequest.action", {
teamId: team_id,
type: type,
csrContent: csr,
appIdId: app_id # optional
})
複製代碼
若建立成功,則在output_path
目錄下存儲此新建立的CSR文件、簽名證書和簽名證書對應的私鑰。 AppleID帳戶下,相同類型的證書只能建立兩個,若是已經建立了兩個以後,再去嘗試建立證書,則會報錯。
security
命令來導入security import certificate_path -k keychain_path -P certificate_password -T /usr/bin/codesign -T /usr/bin/security
複製代碼
其中certificate_path
表示要導入證書的路徑; keychain_path
表示鑰匙鏈的路徑,通常是~/Library/Keychains/login.keychain-db
; certificate_password
表示證書的密碼,默認是空字符串,經過cert
建立的證書的密碼爲空; -T usr/bin/codesign
表示使用usr/bin/codesign
訪問這個證書的時候不須要受權,也就是不須要輸入鑰匙鏈的密碼,這個在CI中會頗有用。 最後須要注意的是,若是證書原本就是在鑰匙鏈中,則不會執行這個步驟,也不會執行這條命令,因此在CI中使用時,最好在構建腳本中加上security unlock-keychain -p certificate_password ~/Library/Keychains/login.keychain-db
,這條命令的做用和上面的-T
相似,可是範圍更廣,即訪問整個鑰匙鏈都不須要輸入密碼。
CER_CERTIFICATE_ID
和CER_FILE_PATH
這兩個環境變量,分別表示證書的id和證書的路徑,證書的路徑就是:output_path
目錄下的證書文件的路徑。 若是是在lane中調用cert
,則還會設置環境變量SIGH_CERTIFICATE_ID
,這樣設置以後,若是接下來sigh
須要建立一個配置文件,就會使用環境變量SIGH_CERTIFICATE_ID
指向的簽名證書來建立。(環境變量SIGH_CERTIFICATE_ID
僅僅只是在建立新的配置文件的時候纔會使用):development
指定證書的類型,true表示調試證書,false表示生產證書,默認是false,本步驟只獲取指定類型的證書。證書列表中的對象的類型都是Spaceship::Portal::Certificate
或其子類。 類Spaceship::Portal::Certificate
中的實例變量module Spaceship
module Portal
class Certificate < PortalBase
# @return (String) The ID given from the developer portal. You'll probably not need it.
attr_accessor :id
# @return (String) The name of the certificate
attr_accessor :name
# @return (String) Status of the certificate
attr_accessor :status
# @return (Date) The date and time when the certificate was created
attr_accessor :created
# @return (Date) The date and time when the certificate will expire
attr_accessor :expires
# @return (String) The owner type that defines if it's a push profile or a code signing identity
# @example Code Signing Identity
# "team"
# @example Push Certificate
# "bundle"
attr_accessor :owner_type
# @return (String) The name of the owner
# @example Code Signing Identity (usually the company name)
# "SunApps Gmbh"
# @example Push Certificate (the bundle identifier)
# "tools.fastlane.app"
attr_accessor :owner_name
# @return (String) The ID of the owner, that can be used to fetch more information
attr_accessor :owner_id
# Indicates the type of this certificate
attr_accessor :type_display_id
# @return (Bool) Whether or not the certificate can be downloaded
attr_accessor :can_download
end
end
end
複製代碼
<Spaceship::Portal::Certificate::InHouse
id="GF0ZY66W6D",
name="iOS Distribution",
status="Issued",
created=2017-12-19 02:52:11 UTC,
expires=2020-12-18 02:42:11 UTC,
owner_type="team",
owner_name="Communications Corporation Limited",
owner_id="12GF5VQGBX",
type_display_id="9RQEK7MSXA",
can_download=true>
複製代碼
r = request(:get, "account/#{platform_slug(mac)}/certificate/downloadCertificateContent.action", {
teamId: team_id,
certificateId: certificate_id,
type: type
})
複製代碼
將下載的證書文件存儲在:output_path
指向的目錄中,指定文件名爲#{certificate.id}.cer
,certificate.id
表示上述證書對象的id。
SHA1
摘要來判斷其是否存在。 使用security find-identity -v -p codesigning
獲取鑰匙鏈中可用的簽名證書列表,下列每一條數據都包含了證書的SHA1
摘要和其名稱wang:temp mac$ security find-identity -v -p codesigning
1) 9C3C5AE7820F33F6D919595E971C9B458519ACE5 "iPhone Developer"
2) 57F720F51EA851BA8E2D6EC4D4D752F9EF43D2F7 "iPhone Distribution"
2 valid identities found
複製代碼
而後獲取[步驟3]中證書文件的SHA1
摘要,若是這個摘要存在於上述輸出中,則表示這個證書已經在鑰匙鏈中了,執行[步驟8] 若是沒有包含,則執行[步驟5]
output_path中檢測私鑰 檢測:output_path
目錄中是否存在#{certificate.id}.p12
,certificate.id
表示[步驟2]中獲取的證書對象的id,這裏是僅僅只是經過文件名來判斷其是否存在。 若存在,說明本地存在可用證書,則執行[步驟8] 若不存在,說明本地不存在可用證書,則執行[步驟6]
從output_path中刪除此證書 刪除[步驟3]中下載的證書文件
本地沒有可用證書
本地有可用證書
sigh
是用於管理配置文件profile,在 sigh
這個Tool中,其內部集成了多個Command,分別是renew、download_all、repair、resign、manage
,其中默認Command是renew
。 renew
的做用是從AppleID帳號中獲取一個可用的配置文件profile,若是沒有,則建立一個新的profile,而後將它按照到xcode中。
這裏只討論renew
,若是沒有特殊說明,指的都是這種狀況。 當在終端執行fastlane sigh [renew]
時,其執行邏輯以下
前幾步與cert
相似,只是有一些用來傳值的環境變量有些不一樣。
獲取AppleID 可經過:username
、環境變量SIGH_USERNAME、DELIVER_USER、DELIVER_USERNAME
或Appfile
三種途徑獲取;若是沒有,則在終端請求用戶輸入AppleID。
獲取AppleID對應密碼
登陸到蘋果開發網站
獲取TeamID 經過環境變量FASTLANE_TEAM_ID
、環境變量SIGH_TEAM_ID
或:team_id
指定TeamID,經過環境變量FASTLANE_TEAM_NAME
,環境變量SIGH_TEAM_NAME
或:team_name
指定TeamName
獲取profile列表 首先從AppleID帳號中,獲取全部已建立的provisioning profiles的列表(也包含xcode管理的),而後通過一步步的過濾,最終獲得全部可用的profile。 5.1 獲取的profile列表有值,則執行[步驟6] 5.2 獲取的profile列表有值,則執行[步驟16]
獲取第一個profile
檢測force :force
指定是否強制建立新的provisioning profile 7.1 :force
等於true,執行[步驟8] 7.2 :force
等於false,執行[步驟10]
在AppleID中刪除此profile 在AppleID帳號中,刪除[步驟6]中獲取的profile
在AppleID中建立新的profile 若是是[步驟16]跳轉過來的,還須要保證AppleID帳號中存在此:app_identifier
返回profile 若是:force
等於true,則返回[步驟9]中建立的profile; 若是:force
等於false,則返回[步驟6]中獲取的profile.
下載profile文件 以前步驟中提到profile是provisioning profile的概要描述,這裏下載的profile文件,則是在項目中使用的配置文件。下載完成後,將文件存儲在臨時目錄中。
output_path目錄下存儲profile文件 將[步驟11]下載的文件移動到:output_path
目錄下,若是指定了:filename
,則文件名爲#{filename}.mobileprovision
;不然,文件名爲#{type}_#{app_identifier}.mobileprovision
,其中type表示prifile的類型,多是AppStore、AdHoc、InHouse和Development。
檢測skip_install :skip_install
指定是否安裝profile到鑰匙鏈中 若是:skip_install
等於true,則執行[步驟15] 若是:skip_install
等於false,則執行[步驟14]
安裝profile到鑰匙鏈中 將[步驟12]中的profile文件複製到~/Library/MobileDevice/Provisioning Profiles/
目錄下,文件名爲#{uuid}.mobileprovision
,其中uuid
指的是profile的uuid
返回output_path路徑 返回:output_path
指定的目錄路徑,而後退出程序
檢測readonly :readonly
指定是否在AppleID帳號中建立新的profile 若是:readonly
等於false,則執行[步驟9] 若是:readonly
等於true,異常退出
獲取全部已建立的provisioning profiles的列表,而後通過一步步的過濾,最終獲得全部可用的profile。
下載全部的profile 全部的pofile是指AppleID帳號中看獲得的全部provisioning profile(即便是invalid)和經過xcode建立的,經過xcode建立的profile不會顯示在AppleID中。
檢測development和adhoc :development
和:adhoc
用來指定profile的類型,profile的類型總共有四種,分別是Development、AppStore、AdHoc、InHouse
檢測force 若是:force
是true,則不會刪除不可用的profile,由於後面會強制建立新的profile,不會使用當前這些profile,也就無所謂可用仍是不可用了。
過濾adhoc或appstore 下面是sigh
的源碼,我的猜想,下載profile時,返回的json數據中有一個叫作distributionMethod
的key,這個key的取值範圍是['inhouse', 'store', 'limited', 'direct']。adhoc
和appstore
類型的profile返回的distributionMethod
的值都是store。在本步驟以前都沒有區分adhoc
和appstore
,在這一步驟中,會根據profile中是否帶有device來區分這兩種類型。
klass = case attrs['distributionMethod']
when 'limited'
Development
when 'store'
AppStore
when 'inhouse'
InHouse
when 'direct'
Direct # Mac-only
else
raise "Can't find class '#{attrs['distributionMethod']}'"
end
複製代碼
下面是建立profile時,請求的參數
params = {
teamId: team_id,
provisioningProfileName: name,
appIdId: app_id,
distributionType: distribution_method,
certificateIds: certificate_ids,
deviceIds: device_ids
}
params[:subPlatform] = sub_platform if sub_platform
# if `template_name` is nil, Default entitlements will be used
params[:template] = template_name if template_name
複製代碼
想要在AppleID帳號中建立新的profile,首先須要獲取上述代碼中的各個參數,主要是簽名證書列表、包含的設備、發佈類型和名稱等
下圖中,步驟1到步驟9都是在篩選可用的簽名證書列表
下載當前平臺和發佈模式的證書列表 好比當前使用的AppleID帳號是一個企業開發者帳號,且:platform
等於ios
,:development
和:adhoc
都等於false
,則在本步驟中會下載ios
平臺下全部的In-House
簽名證書。
檢測cert_id和cert_owner_name :cert_id
是簽名證書的惟一標識符,:cert_owner_name
是簽名證書所屬的team的name。
刪除不匹配的證書 當:cert_id
有值,且證書的cert_id和它不相等,則從證書列表中刪除此證書; :cert_owner_name
有值,且證書的cert_owner_name和它不相等,則從證書列表中刪除此證書;
檢測skip_certificate_verification
刪除不在鑰匙鏈中的證書 檢測證書是否在本地鑰匙鏈,其具體步驟可查看2.1節的步驟4
檢測剩餘證書的數目 剩餘的證書數據爲0,異常退出
檢測development
返回全部剩餘證書 開發環境下的profile能夠包含多個簽名證書,全部返回全部的剩餘證書
返回剩餘證書中的第一個 生產環境下的profile只能包含一個簽名證書,全部返回剩餘證書中的第一個。若是想使用特定的簽名證書,最好使用:cert_id
指定。
獲取profile的name 首先,若是有設置:provisioning_name
,則使用設置的值做爲profile的name;不然,使用#{bundle_id} #{profile_type}
這種格式,好比com.fastlane.demo InHouse
而後,若是skip_fetch_profiles
的值是fasle,則會去檢測這個名字是否已經被使用了,若是被使用了,就在這個名字後面加上一個空格和一個當前的時間戳。
獲取註冊設備的ids 若是當前的發佈模式是AppStore、InHouse、Direct
,即development=false and adhoc=false
,ids等於空數組; 不然,ids等於當前平臺的全部註冊設備的id集合;
獲取其餘參數 其餘參數還包含:team_id、:app_identifier、:template_name
等,:app_identifier
指定的bundle_id必須在AppleID帳號中有建立對應的App ID,不然會異常退出。
生成併發出建立profile的請求 到了這一步,建立profile請求的參數都已經獲取到了,接下來就是發出這個請求。
下面再來看看建立profile時的請求參數
params = {
teamId: team_id,
provisioningProfileName: name,
appIdId: app_id,
distributionType: distribution_method,
certificateIds: certificate_ids,
deviceIds: device_ids
}
params[:subPlatform] = sub_platform if sub_platform
# if `template_name` is nil, Default entitlements will be used
params[:template] = template_name if template_name
複製代碼
建立profile的前提就是要構建好上述代碼中的參數,而這些參數又依賴於執行fastlane sigh
時傳入的外部參數。
下面列出了一些請求參數與外部參數的對照關係
請求參數 | 外部參數 |
---|---|
teamId | :team_id |
provisioningProfileName | :provisioning_name |
appIdId | :app_identifier |
distributionType | :adhoc、:development |
certificateIds | :cert_id、:cert_owner_name |
deviceIds | :platform、:development、:adhoc |
subPlatform | :platform |
template | template_name |
經過:platform
,能夠指定建立profile時的平臺。它有三種取值,分別是mac、ios、tvos
。
當:platform
等於mac
或ios
時,請求參數subPlatform等於nil;不然subPlatform等於tvos
。