この記事はCircleCI Advent Calendar 2015 - Qiitaの14日目の記事です。
13日目はnofrmmさんですが、まだ記事が無いようです。
余談
本当は、CircleCIでのiOSビルドの有料化に伴って、個人アプリのビルドをTravisCIに移したという話をしようと思いましたが、今でもCircleCIでビルド出来てる(金は払ってない)っぽいので、一旦移行はやめました。
なので、社内で実際に構築した別のことをまとめました。
背景
iOSアプリを受託で作る場合、いろいろ面倒ですよね。主に証明書周りが。
弊社でよくあるパターンとしては、
- iTunes connectなどはお客さんしか入れない。
- 証明書はもらえる。
- UDIDが増えたら、お客さんに連絡→provisioningを発行してもらう。
- ipaファイルを納品する。
という感じです。
そのため、証明書やprovisioning profileを動的に取得することは不可能で、Gitのリポジトリに含めることが多いです。
また、弊社ではすでにCircleCIのiOS Planに課金をしており、CircleCI上でiOSのビルドをシェルスクリプトベースで実行していました。
今回、fastlaneというものが、どうやら便利らしいという噂を聞きつけ、試してみました。
実現すること
CircleCI上で動作させるbeta
というlaneを作成し、下記の手順を実行します。
- 証明書のインストール
- ipaファイルの作成
- CircleCIのArtifactsとしてipaを登録
- DeployGateにサブミット
- 証明書のアンインストール
導入手順
一通り設定したものが、noboru-i/kyouen-ios at bcbca4f21be08d56242e23a44f04986496515bd3こちらになります。
こちらでは、SwiftLintの実行なども入っていますが、それはまた別の機会に。
Gemfileの作成・設定
source 'https://rubygems.org'
gem 'fastlane'
上記内容でGemfile
を作成し、bundle install --path vendor/bundle
でインストールを実行します。
fastlaneの初期化
bundle exec fastlane init
というコマンドがありますが、実体としては後述のAppfile
やFastfile
などを質問に答えていくことで作ってくれる、というものなので、今回は実行せずに進みます。
手動で、下記のようなディレクトリ構成を作成します。
プロジェクトのルートディレクトリにfastlane
ディレクトリを作成し、fastlaneで必要なものを配置していきます。
project_root
├── Gemfile
├── circle.yml
└── fastlane
├── Appfile
├── Fastfile
├── actions
│ └── swiftlint.rb
└── cert
├── 02b06950-dd9a-4a2f-8f74-097ed2dd2db7.mobileprovision
├── apple.cer
└── dist.p12
cert
ディレクトリ内のファイルについては、下記のように配置します。
- ファイル名がUUIDとなっているprovisioning profileを配置(インストール済みのものは、
~/Library/MobileDevice/Provisioning Profiles
に格納されているはず。) - Apple Worldwide Developer Relations Certification Authorityと呼ばれるものを、
apple.cer
というファイル名で配置 -
p12
ファイルはパスワードを設定の上、配置(キーチェーンアクセスより、パスワード付きで書き出せる。p12ファイルが最悪流出しても、パスワードがわからなければ利用できない。)
fastlane/Appfileの設定
こちらは、Bundle Identifierなどのツール全般の設定を行うファイルです。
詳しい説明は、こちらを確認ください。
今回は、プロジェクトの設定ファイルにある値をそのまま利用するので、ファイルだけ作成しておき、空にしています。
fastlane/Fastfileの設定
こちらは、laneと呼ばれる実行する処理を記述するファイルです。
詳しい説明はこちら、各アクションのパラメータなどはこちらに記載がありますが、こちらにあるコードを直接見たほうが早いかもしれません。
今回は、前述のbeta
というlaneを定義するために、下記のように設定します。
各アプリ毎に変更が必要な箇所は、先頭にまとめてあります。(You need to set your project values.の部分)
環境に合わせて書き換えて頂ければと思います。
fastlane_version '1.47.0'
default_platform :ios
# You need to set your project values.
workspace_name = 'Sample.xcworkspace'
scheme_name = 'Sample_adhoc'
deploygate_user_name = 'sample-user'
project_name = 'Sample'
# And you need to set environment variables.
# DEPLOY_GATE_KEY : DeployGate API key, using when upload to DeployGate.
# GITHUB_ACCESS_TOKEN : GitHub access token, using when comment to Pull Request.
# KEY_PASSWORD : p12 password, using when import *.p12 files.
platform :ios do
before_all do
add_keychain if is_ci?
end
after_all do
remove_keychain if is_ci?
end
desc 'Submit a new Beta Build to DeployGate'
lane :beta do
gym(
workspace: workspace_name,
scheme: scheme_name,
output_name: "#{project_name}.ipa"
)
Helper.log.info 'Save Artifacts'
sh "cp #{lane_context[SharedValues::IPA_OUTPUT_PATH]} $CIRCLE_ARTIFACTS"
message = "Commit: #{ENV['CIRCLE_SHA1']} / #{last_git_commit[:message]}, Build: #{ENV['CIRCLE_BUILD_NUM']}"
deploygate(
api_token: ENV['DEPLOY_GATE_KEY'],
user: deploygate_user_name,
ipa: lane_context[SharedValues::IPA_OUTPUT_PATH],
message: message
)
end
private_lane :add_keychain do
create_keychain(
name: 'ios-build.keychain',
password: SecureRandom.uuid,
default_keychain: true,
unlock: true,
timeout: 3600,
lock_when_sleeps: true
)
import_certificate keychain_name: 'ios-build.keychain', certificate_path: 'fastlane/cert/apple.cer'
Dir.glob('cert/*.p12').each do |cert_file|
import_certificate keychain_name: 'ios-build.keychain', certificate_path: 'fastlane/' + cert_file, certificate_password: ENV['KEY_PASSWORD']
end
Dir.glob('cert/*.mobileprovision').each do |provisioning_file|
FastlaneCore::ProvisioningProfile.install(provisioning_file)
end
end
private_lane :remove_keychain do
delete_keychain(
name: 'ios-build.keychain'
)
sh "rm -f \"#{FastlaneCore::ProvisioningProfile.profiles_path}*\""
end
end
外部公開用のlaneとしてbeta
があり、それ以外はprivate_laneとしてメソッドを切り出しているイメージです。
CircleCIの設定
上記までで、bundle exec fastlane beta
を実行することで当初の目的を果たせるようになりました。
あとは、これをCircleCI上で実行するように、circle.yml
を下記のようにします。
machine:
timezone: Asia/Tokyo
xcode:
version: "7.1"
test:
override:
- echo 'no test'
deployment:
master:
branch: master
commands:
- bundle exec fastlane beta
ここでは、master
ブランチの変更があった場合に、beta
を実行するようにしています。
最後に、CircleCI上でenvironment variablesの設定を行います。設定が必要な項目はFastfileに記載してあります。(And you need to set environment variables.の部分)
あ、CircleCIのProject setting -> Experimental SettingsでBuild iOS projectをOnにすることもお忘れなく。(CircleCIへの課金が必要)
完成
この設定を行うことで、「XXさんが手が離せないのでアプリの配布が出来ません!」だったり、「XXさんが作ったipaとYYさんがつくったipaで動作が違うんだけど」とか、「ipaの作成作業が面倒なので、DeployGateでの配布は1日1回までとさせて頂きます」といったことから開放されます。
今回は、fastlaneの中でもgym
やdeploygate
といったアクションぐらいしか使っていないですが、provisioning profileの更新や、iTunes connectとの連携など、様々なものが定義されています。
実際やってみて、パス周りだったり、パラメータの意味を調べるのだったりに時間がかかってしまいましたが、今まで慣れないシェルスクリプトで頑張っていたことを考えると、Rubyのコードで拡張していけるようになっただけでも、良かったと思います。