iOSアプリの継続的デリバリーに便利なfastlaneのご紹介

[KrauseFx/fastlane](https://github.com/KrauseFx/fastlane)

# 追記(2015/12/04 14:58)
[fastlaneを使って継続的デリバリーを実践する - Qiita](http://qiita.com/gin0606/items/a8573b582752de0c15e1)

この記事は大分古いfastlaneで書いたものなので、最新のfastlane(1.43.0)で新しく文章を書きました。

この記事の内容は古いものの、まだ使えるのでどちらもよろしくお願いします。

---

継続的デリバリーの正しい定義、探したけどコレという感じのが無かったので、このエントリでは「いつでもリリース可能な状態にして、リリース時のコストを下げておくこと」という定義とします。

fastlaneは、リリースコストを下げることを目的として作られたツール群で、実際に使ってみるとめちゃくちゃ簡単にbeta配信まで出来てしまう。

作者のKrauseFx氏が実際に使っていて、すでに大体の機能は揃っている。fastlane内で使う機能のことをActionと言って、Actionを組み合わせて色々出来る。

機能的にはiTunesConnectへのsubmitまで出来るんだけど、それはまだ使ったことがないのでbeta配信までの手順を紹介する。

# 準備
## インストール
```sh
$ gem install fastlane
```

とするか、*Gemfile*に`gem "fastlane"`って書いて`bundle install`で使えるようになる。

## セットアップ
```sh
$ fastlane init
```

を実行すると色々聞かれるので答える。初見だと英語にビビって硬直する。

* *Do you want to get started? This will move your Deliverfile and Snapfile (if they exist) (y/n)*
  * 使いはじめるか聞いてるので`y`を押す
*  *Do you have everything commited in version control? If not please do so! (y/n)*
  * バージョンコントロールツールでちゃんと全部コミットした？してなかったらちゃんとしといてね！
    * 全部コミット済みであれば`y`
    * まだであれば全部コミットしてから`y`にして先に進む。
* *App Identifier (com.krausefx.app):*
  * fastlaneを使いはじめるアプリのBundle Identifierを入力する
* *Your Apple ID (fastlane@krausefx.com):*
  * 自分のAppleIDを入力する。プロビジョニングプロファイルとか作れるアカウントだと嬉しいけど、ダウンロード出来るアカウントなら大丈夫
* *Do you want to setup 'deliver', which is used to upload app screenshots, app metadata and app updates to the App Store or Apple TestFlight? (y/n)*
  * アプリをAppStoreとかTestflightに上げるか聞いてる。このエントリでは対象としないので`n`
    * `y`にして使ってみるならブログとか書いて手順とかハマりポイント教えて欲しい

ここまで済むと*fastlane*っていうフォルダが出来ていると思うので、`git add`とか`git commit`しておく。

準備終わり

# 使ってみる
```sh
$ fastlane test
```

ってするとシミュレーター立ち上がりまくる。

これは、fastlaneのスクリーンショット撮ってくれる機能で、AppStoreにsubmitする時の画面とかの画像を自動で撮ってくれる。

snapshot.jsにUI Automationで画面遷移とかの操作書いて、captureLocalizedScreenshot呼ぶと撮ってくれる。

ちゃんと使ったことないので使った人居たらブログとか書いて欲しい。

* [Automating UI Testing](https://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/InstrumentsUserGuide/UsingtheAutomationInstrument/UsingtheAutomationInstrument.html)
* [KrauseFx/snapshot](https://github.com/KrauseFx/snapshot)

英語頑張って読める人は普通に使えると思う。

# 自分好みにしてみる
`fastlane init`して作られる*Fastfile*にfastlaneに実行させたいActionを書いていく。それをfastlaneでは*lane*って言う。レーン。

何も触ってない状態の動作は

* すべてのレーンの前に`cocoapods install`とipa作られる
* `lane :test`はsnapshot
* `lane :beta`はsnapshotとsighというプロビジョニングプロファイル取ってくる機能
  * deployも同じ

という感じになってる。

これを

* すべてのレーンの前にcocoapodsインストールする
* `lane :test`ではユニットテスト走らせたい
* `lane :inhouse`を作って社内配信に使いたい
* `lane :beta`は社外のテスターさんとかに配信したい
* `lane :deploy`はiTunesConnectにsubmitしたいけどこのエントリでは扱わない

というような感じに変える。

全部*Fastfile*を編集します。

## すべてのレーンの前にcocoapodsインストールする
レーンの前に実行させる処理は`before_all`に書いてある。

なのでbefore_allにcocoapodsだけ書けばlaneの前には`pod install`が走るだけになる

```ruby
before_all do
  cocoapods
end
```

他にも何かしたい場合はここに書けばOK

## `lane :test`ではユニットテスト走らせたい
ユニットテストは`xctest`というActionで実行できる

```ruby
desc "Runs all the tests"
lane :test do
  xctest(
    scheme: "ExampleApp",
    destination: "platform=iOS Simulator,name=iPhone 6,OS=8.4",
  )
end
```

最低でもこれだけ書けばユニットテスト走る。

プロジェクト見つけてくれなかったり、他になにか問題があったら`$ fastlane actions xctest`でxctestに渡すパラメタ確認して適切なのを設定する。

## `lane :inhouse`を作って社内配信に使いたい
新しいlaneは、既存のレーンと同じように`lane :inhouse`とか書けば作れる。

```ruby
desc "社内向け配信"
lane :inhouse do
end
```

`lane :test`のしたとかに書けば`$ fastlane inhouse`呼べる。

実際の処理はこんな感じ。

```ruby
desc "社内向け配信"
lane :inhouse do
  sigh(
    adhoc: true,
  )
  ipa(
    configuration: 'Release',
  )
  deploygate(
    user: '',
    api_token: ''
  )
end
```

CircleCIとか使ってる場合は、これとは別にキーチェーン登録したりしないといけないんだけど、それは後述する。

### sigh
プロビジョニングプロファイル作ったりダウンロードしてくれるやつ。

設定したAppleIDのアカウントから対象のアプリで使えるプロビジョニングプロファイルを作ったりダウンロードしてくれる。権限ない場合は、予め作っておけばダウンロードしてくれる。

自動で使える状態にしてくれてて、`ENV["SIGH_PROFILE_FILE_NAME"]`にパスが入ってる。

### ipa
ipa作ってくれる。

大体書いたとおりでipa作ってくれると思う。作れなかったらxcodebuildのリファレンス見たり`$ fastlane actions ipa`見て頑張って欲しい。その結果をブログとかに書こう。

### deploygate
deploygateに配信してくれるやつ。

https://github.com/KrauseFx/fastlane/blob/master/docs/Actions.md#deploying

対応してるサービスはここに書いてある。対応してないやつを使いたかったらAction作ってプルリクエスト送ろう。

ここではdeploygate使ってるけど、Crashlytics Betaに移行しようと思ってる。

## `lane :beta`は社外のテスターさんとかに配信したい
Action自体はinhouseの配信先変えるだけで使える。

ただ、社内向け配信対象の人もダウンロードしたい場合はBundleID変える必要あるので、その方法。

### Appfileを編集する
```ruby
for_platform :ios do
  # app_identifier "me.gin0606.ExampleApp.default"
  for_lane :inhouse do
    app_identifier "me.gin0606.ExampleApp"
  end

  for_lane :beta do
    app_identifier "me.gin0606.ExampleApp.beta"
  end
end
```

これは、laneごとに使用するapp_identifierを変えてくれる書き方。

コメントアウトしているけど、for_laneの外に何か書いておけば、指定したレーン以外だとそれが使われるはず。

### Fastfileを編集する
```ruby
lane :inhouse do
  update_info_plist(
    plist_path: 'ExampleApp/Info.plist',
    app_identifier: 'me.gin0606.ExampleApp.beta',
  )
  # `lane :inhouse`の中身コピペ
end
```

こういうのも重複なくしたいとかいうのあったらbundleID変えるだけのlaneとか作ればいいと思う。

[fastlane - iOS Automation for Continuous Delivery](https://fastlane.tools/)

ここにあるレーンの図的に、各レーンは独立したものなので、個人的にはコピペしていいんじゃないかと思ってる。

## CircleCIなどで署名できるようにする
fastlaneが含んでるツール群の中にはsighみたいな感じで証明書扱ってくれるやつもあるんだけど、sighほど機能が充実していないっぽい感じになってる。

certは証明書を作って、loginキーチェーンに登録までしてくれるんだけど、CircleCIなど使ってる場合は毎回証明書作る感じになる。

なので、既存の証明書をCircleCI等のキーチェーンに登録できるActionを作ってプルリクエスト出した。

[Add actions for certificate by gin0606 · Pull Request #380 · KrauseFx/fastlane](https://github.com/KrauseFx/fastlane/pull/380)

```ruby
create_keychain(
  default_keychain: true,
  unlock: true,
  timeout: 3600,
  lock_when_sleeps: true
)
import_certificate certificate_path: "certs/AppleWWDRCA.cer"
import_certificate certificate_path: "certs/dist.p12", certificate_password: ENV['MY_DIST_CERT_PASSWORD']
```

`ENV['KEYCHAIN_NAME']`, `ENV['KEYCHAIN_PASSWORD']`, `ENV['MY_DIST_CERT_PASSWORD']`は各Actionのパラメタとしても渡せるんだけど、環境変数で渡したほうが良いと思う。

# 終わり
以上で恐らく大体のアプリで使うようなテスト〜beta配信までのコストが低まると思う。

`$ fastlane actions`で組み込まれてるActionの一覧が見られて、`$ fastlane actions [action_name]`でそのActionの詳細が見られる。

この前あったfastlane meetupで作者のKrauseFx氏が自分が使わない機能の開発はそんなに力を入れてないって言ってたので、自分たちの環境で必要なActionがあったら汎用的に作ってプルリクエスト出したらみんなハッピーって感じだと思う。

結構寛容な心でレビューをしてくれる。

以上に書いたことをやろうとする上で、なにか問題があったら頑張って解決して、その内容を自分のブログなりQiitaに書いて欲しいみたいな感じ。

[fastlane for Android · Issue #169 · KrauseFx/fastlane](https://github.com/KrauseFx/fastlane/issues/169)

Androidも対応予定はあるんだけど、そんなに本腰入れてないらしいのでコントリビュートチャンス。

# おまけ
[fastlane meetupでLTしてきた #fastlane_jp - 銀の人のメモ帳](http://gin0606.hatenablog.com/entry/2015/06/26/233945)

新しいActionの作り方はここに書いてる。

基本的には`self.run`のなかに色々書いてく。あとは頑張れ。

## circle.yaml大公開
こんな感じでCircleCIからbeta配信してる。

```yaml
machine:
  xcode:
    version: "6.3.1"

dependencies:
  post:
    - openssl aes-256-cbc -k "$DIST_P12_ENC_KEY" -in certs/dist.p12.enc -d -a -out certs/dist.p12

test:
  override:
    - bundle exec fastlane test

deployment:
  development:
    branch: master
    commands:
      - bundle exec fastlane keychain
      - bundle exec fastlane inhouse
  beta:
    branch: staging
    commands:
      - bundle exec fastlane keychain
      - bundle exec fastlane beta
```

## fastlaneがなかった時代
https://gist.github.com/gin0606/9970458

こんなスクリプト書いて頑張ってた。

[Nomad - World-Class Command Line Utilities For iOS Development](http://nomad-cli.com/)

nomadのツール群使えばもっと簡単になったと思うけど、僕個人のnomadへの信頼感が低かった。fastlaneの一部Actionからもnomadのツール群の機能が使われてる。