前書き
iOS 開発において「証明書」という単語を聞くだけでアレルギー反応を起こす人も少なくないかもしれません。
iOS 開発チームにメンバーが追加された際は、少なくとも以下のような作業を行ってもらう(もしくは、行う)必要があります。
- Apple Developer アカウントの作成
- Apple Develper Portal(以下、Dev Portal)にメンバーを招待
- コード署名証明書(以下、証明書)の作成
- プロビジョニングプロファイル(以下、プロファイル)の更新
これらの作業を手動で行うのには非常に手間がかかります。
Xcode 8 から Automatic Signing が導入されましたが、証明書管理が iOS 開発チームの各メンバーに依存することにより発生する証明書周りのトラブルは後を絶ちません。個人開発では発生しなかったトラブルがチーム開発では付いて回ります。
また、CI 上で証明書とプロファイルをどのように扱うかといった課題も残ります。
そこで fastlane match(以下、match) です。
match のアプローチについてはこちらに記載されています。
match とは
match は、iOS 開発チームで共通の証明書とプロファイルの作成や維持を行い、プライベートリポジトリに格納、そして全ての開発者間で共有できるようにします。
つまり、メンバーが増える度に Apple Developer アカウントや証明書を作成する必要がなくなります。
構成は以下をご覧下さい。
ざっくり説明すると、以下の2点が運用される状態を作ろうと思いました。
- adminに任命された人は、matchを使って証明書& Provisioning Profile の作成&commitを行う
- memberは、matchを使って証明書& Provisioning Profile をダウンロードして使う
引用元:fastlane match でiOSアプリ開発者を「証明書管理の苦しみ」から解放せよ! - BizReach Tech Blog
match の導入
インストール
match は fastlane の action のため、fastlane をインストールすることで match を使用することができます。
fastlane は RubyGems や Homebrew を利用してインストールすることができます。
Gemfile を使用するにはこちらを参照して下さい。
# Using RubyGems
sudo gem install fastlane -NV
# Alternatively using Homebrew
brew cask install fastlane
事前準備
プライベートリポジトリの作成
証明書やプロファイルを保存するためのプライベートな Git リポジトリを作成します。
リポジトリ名は certificates
などにします。
Apple Developer アカウントの用意
チーム全体で共有する Apple Developer アカウントを用意します。(例:office@company.com)
権限を App Manager にして下さい。
App Manager 以上の権限でないと、match を実行した際に以下のようなエラーが発生する場合があります。
[App Store Connect unification] Spaceship::UnexpectedResponse: [!] Apple provided the following error info: Access Unavailable - You currently don't have access to this membership resource
詳しくは、こちらをご覧下さい。
Xcode プロジェクト設定
Xcodeプロジェクトのプロファイルを自動に設定しないでください。常に正しいプロファイルが選択されるわけではありません。
Xcode プロジェクト設定「 General > Automatically manage signing 」を無効にしておきましょう。
詳しくは、こちらをご覧下さい。
App ID の用意
iOS アプリのための App ID を用意します。
produce を使用することで、Dev Portal と App Store Connect の両方に新しい iOS アプリを作成することが可能です。また、アプリケーションサービスの変更やアプリケーショングループの変更も可能です。
-a
もしくは --app_identifier
オプションを使用して、アプリの Bundle Identifier を指定できます。
fastlane produce -a <app_identifier>
-i
もしくは --skip_itc
オプションを使用して、App Store Connect でのアプリ作成をスキップできます。
fastlane produce -a <app_identifier> -i
メンバーの権限設定
App Store Connect の「ユーザーとアクセス」でメンバーの権限を設定できます。
「デベロッパーリソース」の項目から証明書やプロファイルのアクセス権限を設定することが可能です。
こちらにチェックが付いているメンバーは Xcode 上から証明書の更新が可能となってしまいます。
誤って更新されることを防ぐために、管理者ではないメンバーにはアクセス権限を与えないことをお勧めします。
「Certificates, Identifiers & Profile (証明書、ID & プロファイル)」へのアクセスは、組織のチームのメンバーである、App Manager または Developer の役割を持つユーザに追加で割り当てることができる特権です。この権限が追加されたユーザは、すべての App に関連付けられた証明書、ID、およびプロファイルを表示できます。
初期設定
match を使用するための初期設定を行います。
fastlane match init
Git リポジトリの URL や、パスフレーズが要求されるため入力して下さい。
証明書やプロビジョニングプロファイルは openssl
を使用してパスフレーズによって暗号化され、Git リポジトリに保存されます。
そのため、パスフレーズはチームに共有する必要があります。
環境変数を使用して復号化するようにパスフレーズを設定するには、MATCH_PASSWORD
を使用します。
また、上記コマンドを実行すると、カレントディレクトリに Matchfile
が作成されます。
fastlane init
を実行したプロジェクト(以下、fastlane プロジェクト)のプロジェクトルートで上記コマンドを実行した場合は ./fastlane/
に作成されます。
match の実行
fastlane プロジェクトのプロジェクトルート外で match を実行した場合、チーム全体で共有する Apple Developer アカウントの Apple ID や、アプリの Bundle Identifier が要求されるため入力して下さい。
入力を省略したい場合は、カレントディレクトリの Matchfile
を修正して下さい。
app_identifier("<app_identifier>")
username("<username>")
作成
証明書とプロビジョニングプロファイルを作成します。
基本的に管理者が行う作業です。
$ fastlane match development
$ fastlane match adhoc
$ fastlane match appstore
match(type: "development")
match(type: "adhoc")
match(type: "appstore")
既存の証明書とプロファイルを残したまま、match で作成した証明書とプロファイルを混在させ、徐々に移行することも可能です。
match を実行した例は以下をご覧下さい。
具体的な処理の流れ
上記コマンドの具体的な処理の流れは以下をご覧下さい。
- Dev Portal に証明書とプロファイルを作成
- Git リポジトリに証明書(とその秘密鍵)とプロファイルを格納
- プロビジョニングプロファイルが
~/Library/MobileDevice/Provisioning Profiles
にインストール - 証明書と秘密鍵が、キーチェーンにインストール
※ 既に証明書とプロビジョニングプロファイルが作成されている場合は更新されます。
リポジトリの構造
上記コマンド実行後、Git リポジトリには2つのディレクトリが含まれます。
- 証明書とその秘密鍵を含む
certs
ディレクトリ - プロビジョニングプロファイルを含む
profiles
ディレクトリ
具体的にどのような構造になるか確認したい場合は、こちらのサンプルを参照して下さい。
取得
Git リポジトリから証明書とプロビジョニングプロファイルのインストールを行います。
基本的にメンバーが行う作業です。
新規メンバーのマシンに証明書とプロビジョニングプロファイルをインストールしたい場合など、Dev Portal にアクセスする必要がない場合は --readonly
オプションを使用します。
$ fastlane match development --readonly
match(type: "development", readonly: true)
削除
無効や期限切れ、Xcode によって管理された証明書やプロビジョニングプロファイルを Dev Portal から削除します。
$ fastlane match nuke
$ fastlane match nuke development
$ fastlane match nuke distribution
削除される予定の証明書とプロファイルのリストが表示され、削除するかどうかの確認が要求されるため、y
か n
を入力して下さい。
y
を入力し削除しても、App Store と TestFlight で既に利用可能なアプリは引き続き機能します。
※ 初めて match を実行する前に、上記コマンドを使用して既存の証明書とプロファイルの消去を考慮することが推奨されています。match の検証や、既存の証明書とプロファイルを残したい場合は上記コマンドの使用はお勧めしません。
nuke を実行した例は以下をご覧下さい。
パスフレーズの変更
パスフレーズを変更します。
$ fastlane match change_password
実行後、全てのマシンで新しいパスフレーズが要求されます。
新しいデバイスの登録
register_device を使用することで、Dev Portal に新しいデバイスを登録することが可能です。
$ fastlane run register_device name:"<name>" udid:"<udid>"
register_device(
name: "<name>",
udid: "<udid>"
)
--force_for_new_devices
オプションを使用して、Dev Portal のデバイス数が変更されたかどうかを確認し、必要に応じてプロビジョニングプロファイルを自動的に更新します。
$ fastlane match development --force_for_new_devices
$ fastlane match adhoc --force_for_new_devices
match(type: "development", force_for_new_devices: true)
match(type: "adhoc", force_for_new_devices: true)
証明書の更新
証明書の有効期限は1年です。
証明書の期限が切れた状態で match を実行すると、以下のようなエラーが発生します。
[!] Your certificate 'XXXXXXXXXX.cer' is not valid, please check end date and renew it if necessary
以下の二つのソリューションどちらかの実施後に match を再度実行すると、新しい証明書とプロファイルが再作成されます。
基本的に管理者が行う作業です。
証明書の更新が完了したらメンバーに fastlane match development --readonly
を実行して最新の証明書を取得するよう促してください。
1. 証明書とプロビジョニングプロファイルを fastlane match nuke
で削除
前述した nuke を使用して証明書とプロビジョニングプロファイルを全て削除します。
※ nuke は特定の証明書または App ID を選択して削除することはできません。
$ fastlane match nuke development
$ fastlane match nuke distribution
※ 破壊的なため、実施する際は自己責任でお願いします。
2. 証明書とプロビジョニングプロファイルをプライベートリポジトリから手動で削除
特定の証明書やプロビジョニングプロファイル、アプリケーションのみを削除したい場合は、リポジトリ内のファイルを削除するだけです。
/certs/development/XXXXXXXXXX.cer
/certs/development/XXXXXXXXXX.p12
/profiles/development/Development_xxxxxxxxxx.mobileprovision
削除が完了したらリポジトリへプッシュします。
また、リポジトリ内の削除したファイルに対応する Dev Portal 上からプロビジョニングプロファイルを削除する必要があります。
※ Dev Portal 上からプロビジョニングプロファイルを削除しない場合、 ランダムな数字がサフィックスとして追加されたプロファイル名になります(fastlane が名前衝突を避けるため)。
CI で使用
取得
CI 上で match を実行するときは、常に --readonly
オプションを使用することが推奨されています。
lane :beta do
match(type: "appstore", readonly: is_ci)
gym(scheme: "Release")
end
キーチェーンの作成
CI 上で match を実行するときは、キーチェーンを名前とパスワード付きで作成する必要があります。
詳しくは以下をご覧下さい。
具体的には、キーチェーンのパスワードを入力して許可する必要がありました。自分のマシンの場合はログインパスワードを入力すれば良いのですが、CIマシン上での場合は新しくキーチェーンを名前・パスワード付きで作成して、match実行時にそれを用いる、という手順が必要でした。
コードとしては、MATCH_KEYCHAIN_NAME・MATCH_KEYCHAIN_PASSWORDに適当な値を環境変数としてセットした上で、以下をmatchコマンド前に実行すれば解決しました。
引用元:Bitrise Xcode 8.1などのSierra製CIマシンとfastlaneの組み合わせでビルドが固まる問題が解決🎉
before_all do
if is_ci?
create_keychain(
name: ENV['MATCH_KEYCHAIN_NAME'],
password: ENV['MATCH_KEYCHAIN_PASSWORD'],
timeout: 1800
)
end
end
※ AppStore のプロビジョニングプロファイルにはデバイス情報が含まれていないため、プロファイルタイプが appstore
の場合無視されます。