iOSのビルド・テスト・iTunesConnectへのサブミット作業をCircleCI+fastlaneで自動化
2016年 12月 07日
このエントリーは、エキサイト Advent Calendar 2016 の 12/07 の記事です。
エキサイトとしては初のAdvent Calendar参戦です。
こんにちは、Eレシピを担当しています小林です。よろしくお願いします。
今回はiOSのビルド自動化にfastlaneとCircleCIを導入した話になります。
弊社のiOSアプリのサブミット作業自動化は、Jenkins+shellスクリプトで行っておりましたが、今年になってからCircleCI+fastlaneに移行しました。
この記事はそれの導入手順になります。
準備
Xcode8でビルドできるようにしておくXcodeコマンドラインツールを最新にしておく
xcode-select --install
ローカルにbundlerをインストールしておく
sudo gem install bundler
CIから使用する以下の共通アカウントを作成しておく。
- Apple Developer
- iTunes Connect
- Github
fastlane

まずfastlaneを追加します。
Gemfileでの管理が推薦されているのでファイルをプロジェクトトップに追加します。
Gemfile
source "https://rubygems.org"
gem "cocoapods"
gem "fastlane"
インストール
bundle
fastlaneの初期設定をします。プロジェクトトップで、
bundle exec fastlane init
# Apple ID: {作成した共通アカウント}
これでfastlane関連のファイルが作成されます。
match

matchはfastlaneのツールで、証明書をgithub管理してチームでシェアできるようになります。
まずgithubのプライベートリポジトリを、リポジトリ名を certificates などとして作成しておきます。
matchの初期設定をします。プロジェクトトップで、
bundle exec match init
# リポジトリURL: {作成したリポジトリURL}
これで、fastlane/Matchfile が作成されます。
Provisioning Profile作成
Developmentのプロビジョニングを作成します。プロジェクトトップで、bundle exec match development
# Passphrase for Git Repo: {パスワード}
ここで入力したパスワードは、チーム内で共有して忘れないようにしておきます。
新しくDevのProvisioningが生成され、Developer Centerに登録、Githubにpush、ローカルのkechainに登録まで全てツールがやってくれます。
Distributionも作成します。
bundle exec match appstore
これでDevelop Center https://developer.apple.com/account/ios/profile/ に
match AppStore {bundle id} iOS Distribution
match Development {bundle id} iOS Development
が作成されています。
enterprise版もある場合は、ブランチ、AppIdentifier、ユーザー名を以下のように指定して実行します。
bundle exec match appstore --git_branch enterprise --app_identifier {bundle id} -u {エンタープライズのAppleID}
Xcodeの設定変更
Signing設定の部分の Automatically manage signing のチェックを外して、それぞれのProvisioning Profileをmatchで生成したものに変更します。certificatesレーンをfastlane/Fastfileに追加します。
lane :certificates do
match(type: "development", readonly: true)
end
今後開発者が増えた時は、プロジェクトトップで、
bundle exec fastlane certificates
と打ってもらうだけで、開発証明書を共有できます。
deliver

bundle exec deliver init
で、iTC上のスクリーンショットやメタデータを取り込んでバージョン管理するようにします。
ファイル変更
fastlane/Fastfile に、test, beta, tflight, releaseなどの名前でレーンを追加します。Fastfileはプロジェクトごとにカスタマイズすると良いです。
before_all do
# ビルド番号更新
set_info_plist_value(
path: 'Info.plist',
key: 'CFBundleVersion',
value: ENV['CIRCLE_BUILD_NUM']
)
end
lane :test do
cocoapods
scan(scheme: "{スキーム名}")
end
lane :beta do
# 証明書取得
match(
type: "appstore",
app_identifier: "{Bundle id}",
git_branch: "enterprise",
username: "{Apple ID}"
)
# ビルド
gym(
scheme: "{スキーム名}",
configuration: "InHouse",
output_name: "inhouse.ipa"
)
# Betaに送信
crashlytics(
crashlytics_path: "./Pods/Crashlytics/",
ipa_path: "./inhouse.ipa"
)
end
lane :tflight do
match(
type: "appstore",
app_identifier: "{Bundle id}",
username: "{Apple ID}"
)
gym(
scheme: "{Scheme名}",
configuration: "Release",
output_name: "release.ipa"
)
# TestFlightに送信
pilot(
ipa: "./release.ipa"
)
end
lane :release do
match(
type: "appstore",
app_identifier: "{Bundle id}",
username: "{Apple ID}"
)
gym(
scheme: "{スキーム名}",
configuration: "Release",
output_name: "release.ipa"
)
# iTCに送信
deliver(force: true)
end
.gitignoreに追加します。
# fastlane
fastlane/report.xml
fastlane/test_output
Preview.html
バイナリアップロードの部分でエラーにならないように、Info.plistに以下を追加します。
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
ローカルでそれぞれのレーンが成功すればOKです。
bundle exec fastlane test
bundle exec fastlane beta
bundle exec fastlane tflight
bundle exec fastlane release
circle.ymlをプロジェクトトップに追加します。
machine:
timezone: Asia/Tokyo
xcode:
version: "8.1"
dependencies:
pre:
- sudo gem update --system
- sudo gem install bundler
test:
override:
- bundle exec fastlane test
deployment:
beta:
branch: develop
commands:
- bundle exec fastlane beta
- bundle exec fastlane tflight
release:
branch: master
commands:
- bundle exec fastlane release
CircleCIはgithubへのpushがトリガーとなって、CircleCI上でビルドが走ります。push先ブランチが指定ブランチの場合は、testが実行された後にdeploymentが実行されます。
これでファイル追加は終わりなので、コミットしてプルリクを出しておきます。
Circle CI

プロジェクト設定
Circle CIにGithubアカウントでログインします。https://circleci.com/
左メニューの ADD PROJECTS -> OS X -> プロジェクト名をクリックしてプロジェクト画面を開きます。
右上の設定リンクをクリックします。
環境定数設定
BUILD SETTINGS -> Environment Variablesから環境定数を設定します。
FASTLANE_USER: {Apple Developer ID}
FASTLANE_PASSWORD: {Apple Developer Password}
MATCH_PASSWORD: {作成したmatch用パスワード}
CRASHLYTICS_API_TOKEN: {token}
CRASHLYTICS_BUILD_SECRET: {secret}
CRASHLYTICS_GROUPS: {グループ名}
SLACK_URL: {SLACKのWebhook URL}
SSH key設定
PERMISSIONS -> Checkout SSH keysを選択します。証明書用リポジトリなど、複数のリポジトリ間で共通のSSH keyを使う必要があるため、
作成したGithubの共通アカウントでCircleCIにログインし、Authorize with Githubボタンを押して、共通アカウントのSSH keyを登録します。他にPodfileなどでプライベートリポジトリを使用している場合も、同様の方法で共通アカウントのSSH keyを登録します。
ビルドを実行して、すべてのレーンが成功すれば設定完了です!
感想
iOSアプリの一連のサブミット作業の自動化は、一度設定してしまえばそれ以降はその作業をCIに任せられるので、他の作業に集中できます。またJenkinsからCircleCIに移行したことのメリットも大きく、今までは社内に設置されているJenkinsが急に体調不良になりジョブやジョブ履歴が消えたりして、丸一日それの対応に時間が取られることもありましたが、CircleCIではその心配がなくなりました。またmatchやdeliverの機能が想像以上に便利で、matchでは証明書の管理を自動化してくれたり、deliverでは今まではバージョン管理していなかったストア上のメタデータやスクリーンショットなどをバージョン管理するようになったり、何よりもアップロードが完了したらあとはビルドを選択して審査に提出ボタンを押すだけの手軽さに感動しました!まだ試されてない方は是非使ってみてください。明日は2年目エンジニアの壷井くんの、Nginxのリバースプロキシについてのお話です!どうぞお楽しみに!