iOSアプリ開発で面倒なことを解決していく

こんにちは、今年は数年ぶりにiOS開発に戻ってきました。iOS開発面白いですね。ただiOS開発に戻ってきて思うのは、証明書など複雑で面倒なことが多いということです。今回はアプリ開発で面倒なことをfastlaneに任せましょうという話になります。fastlaneの導入や、基本的な使い方は良い記事がたくさんあるので、面倒なことベースで解決方法を紹介していきたいと思います。

# fastlane

まず最初にfastlaneについて簡単な説明です。

![1_txtcYocQEGtOFN33ZCTDbw.png](https://qiita-image-store.s3.amazonaws.com/0/11156/58fe581d-1115-7662-3c5e-dd8aea367385.png)

[GitHub](https://github.com/fastlane/fastlane)には以下のように書いてあります。
> fastlane is a tool for iOS and Android developers to automate tedious tasks like generating screenshots, dealing with provisioning profiles, and releasing your application.

つまりアプリの面倒な作業を簡単にしてくれるツールです。ここ3年間くらいですっかり浸透したツールだと思います。fastlaneではアクションという形で様々な機能が提供されており、アクションの組み合わせをFastfileという設定ファイルに記述して実装していきます。普段面倒だと感じることは大体できるので、まだ導入していない人はぜひ年末に触ってみてください。

# 証明書
それでは面倒なことに入っていきますが、個人的にiOSは証明書周りが面倒です。特にチーム開発だったり仕事で複数のプロジェクトを担当すると顕著にでます。このあたりはfastlaneで自動でやりたいところです。証明書の管理はfastlaneの基本機能の1つなので、すでにやっている方は読み飛ばしてください。

### match
fastlaneにはmatchというアクションがあり、証明書をGitHubで管理し、複数の開発者で共有しやすくできます。手順も非常に簡単です。

1. 管理用のプライベートなリポジトリを用意する
2. 管理者がmatchで証明書を作成する
3. readonlyで証明書を取得し使用する

これだけで「このプロジェクトのアーカイブに必要なProvisioningは...」といった会話が軽減されます。

#### matchで証明書を作成

まず最初にinitをします。証明書管理用のリポジトリが聞かれるのでプライベートリポジトリを入力してください。

```shell
$ fastlane match init                                                                             (git)-[master]
[✔] 🚀
[19:02:34]: Please create a new, private git repository
[19:02:34]: to store the certificates and profiles there
[19:02:34]: URL of the Git Repo: 
```

initをするとMatchfileという設定ファイルが生成されます。
ここに必要な設定を記述していきます。

```ruby
# Matchfile
git_url("最初に作成した管理用プライベートリポジトリが自動で設定されている")
type("デフォルトのタイプappstore, adhoc, enterprise, developmentのいずれを指定")
app_identifier("アプリのBundle Identirierを指定 ex)ほげほげ.FastlaneActions")
username("Apple Developer Portalのユーザー名を指定")
```

記述が終わったら証明書などの作成をします。コマンドを1行打つだけでmatchが必要なことをやってくれます。

```shell

$ fastlane match development                                                                      (git)-[master]
~~
[07:45:58]: 🔓  Successfully decrypted certificates repo
[07:45:58]: To not be asked about this value, you can specify it using 'username'
[07:45:58]: Your Apple ID Username:

# パスワードなどいくつかの質問に答えていって完了
```

パスワード入力などの質問に答えていくと、initで指定したリポジトリにCertificates, p12ファイル, Provisioning Profileが暗号化されてPushされます。

#### readonlyで証明書を取得
管理者が証明書の作成をしたら、あとはreadonlyで使っていきます。
1行打つだけで必要なファイルが揃うので非常に簡単です。

```shell
% fastlane match development --readonly                                                           (git)-[master]
[✔] 🚀
[08:24:21]: All required keys, certificates and provisioning profiles are installed 🙌
```

チームに新しく人が入ってきた場合、別のプロジェクトにアサインされた場合などに管理が非常に楽になりますね。


# バージョン管理
次の面倒なことはバージョン管理です。開発をしているとどこかのタイミングで`Version`と`Build`を上げることになります。「bumpのPRを作成」とかは面倒ですね。その辺もfastlaneに解決をお願いしたいところです。これらは`increment_version_number` `increment_build_number`というアクションを使用して解決します。

### increment_build_number
アクションの説明は[こちら](https://docs.fastlane.tools/actions/increment_build_number/)にありますが、自動でインクリメントをする際、基本的にはincrement_build_numberを1行書けば大丈夫です。

```shell
# Fastfile
  lane :bump_version do
    increment_build_number
  end
```

しかしこのまま実行しても動作しません。おそらく下記のエラーに遭遇します。

```shell
[09:51:38]: Apple Generic Versioning is not enabled in this project.
```

`Build Settings` -> `Versioning`から`Versioning System`を`Apple Generic`にし、`Current Project Version`を指定してください。

<img width="866" alt="スクリーンショット 2018-12-23 10.21.25.png" src="https://qiita-image-store.s3.amazonaws.com/0/11156/c4e16513-031c-e06b-9f7b-136398e83de1.png">
参考：https://developer.apple.com/library/archive/qa/qa1827/_index.html




### increment_version_number

increment_version_numberも同様に1行追加すれば良いですが、注意点としてVersionは`x.x.x`という形式にしておく必要があります。

```shell
# Fastfile
  lane :bump_version do
    increment_build_number
    increment_version_number
  end
```

実行するとバージョンが上がっていくのが分かります。

```shell

$ fastlane bump_version                                                                                                                                   (git)-[master]
[✔] 🚀
~~
Current version of project FastlaneActions is:
    1
[10:22:34]: ▸ Setting version of project FastlaneActions to:
[10:22:34]: ▸ 2.
[10:22:34]: ▸ Also setting CFBundleVersion key (assuming it exists)
[10:22:34]: ▸ Updating CFBundleVersion in Info.plist(s)...
[10:22:34]: ▸ Updated CFBundleVersion in "FastlaneActions.xcodeproj/../FastlaneActions/Info.plist" to 2
[10:22:34]: ▸ Updated CFBundleVersion in
~~
[10:22:35]: --- Step: increment_version_number ---
[10:22:35]: ▸ Setting CFBundleShortVersionString of project FastlaneActions to:
[10:22:35]: ▸ 1.0.1.
[10:22:35]: ▸ Updating CFBundleShortVersionString in Info.plist(s)...
[10:22:35]: ▸ Updated CFBundleShortVersionString in "FastlaneActions.xcodeproj/../FastlaneActions/Info.plist" to 1.0.1
[10:22:35]: ▸ Updated CFBundleShortVersionString in "FastlaneActions.xcodeproj/../FastlaneActionsTests/Info.plist" to 1.0.1
[10:22:35]: ▸ Updated CFBundleShortVersionString in "FastlaneActions.xcodeproj/../FastlaneActionsUITests/Info.plist" to 1.0.1
[10:22:35]: fastlane.tools finished successfully 🎉
```


### commitとGitHubへのPush
バージョンを進めたらcommitをしてGitHubへのPushを行います。
[commit_version_bump](https://docs.fastlane.tools/actions/commit_version_bump/)や[push_to_git_remote](https://docs.fastlane.tools/actions/push_to_git_remote/)といったアクションが使えますので、適宜設定していきます。

```shell
# Fastfile
  lane :bump_version do
    increment_build_number
    increment_version_number
    clean_build_artifacts
    commit_version_bump(xcodeproj: "./FastlaneActions.xcodeproj", force: true)
    push_to_git_remote
  end
```
# βバージョンの配布
次はβバージョンの配布についてです。業務の場合、開発したアプリをプロジェクト関係者に配布することがあると思います。おそらく配布にはTestFlightやFabric Beta、DeployGateなどを使用していると思いますが、ビルドから配布までfastlaneに任せます。

### ビルド

ビルドには[gym](https://docs.fastlane.tools/actions/gym/)というアクションを使います。

```ruby
# Fastfile
  gym(scheme: "FastlaneActions",
    configuration: "Debug",
    clean: true,
    export_method: "development"
  )
```
### デプロイ
Testflights、HockeyApp、Fabric Beta、TestFairyなど各テスティングサービスのアクションが揃っています。今回はDeployGateをサンプルに使用します。DeployGateにアップロードするアクションも用意されており、APIトークンなどを指定することでDeployGateへのアップロードも簡単に行えます。

```ruby
# Fastfile
  deploygate(
    api_token: ENV["DEPLOYGATE_API_TOKEN"],
    user: "HogeMan",
    ipa: "./FastlaneActions.ipa",
    message: "Fastlane build #{lane_context[SharedValues::BUILD_NUMBER]}"
  )
```

### アプリアイコン
プロジェクトメンバーにβ版の配布を行う際、サーバーの向き先が本番と開発で違うアプリを用意するケースなども出てきます。DisplayNameだけだとパッと見わかりません。ここもfastlaneに何とかしてもらいましょう。

#### budge
fastlaneに`budge`というプラグインがあります。
https://github.com/HazAT/fastlane-plugin-badge

こちらを使用してアイコンに分かりやすいバッジをつけることができます。


```shell
# Fastfile
  lane :beta_badge do
    add_badge(shield: "Version-1.0.0-blue", dark: true)
  end
```

```shell
fastlane add_plugin beta_badge
```

上記を実行するとアイコン画像が書き変わります。

<img width="549" alt="スクリーンショット 2018-12-23 20.51.05.png" src="https://qiita-image-store.s3.amazonaws.com/0/11156/6f872994-fb1d-2077-5388-3540799ee76d.png">


確認用のアプリを分かりやすくして確認間違いを防ぎたいですね。

![Simulator Screen Shot - iPhone XR - 2018-12-23 at 17.54.31.png](https://qiita-image-store.s3.amazonaws.com/0/11156/4cdd23ec-4ba8-d5bb-fdda-e551d38fa599.png)

[lane_context](https://docs.fastlane.tools/actions/lane_context/)を使用して、アプリ判断がつきやすいバッジをつけると良いかと思います。

# タグ
次はタグの管理です。Gitのタグ機能を使用している人が多いと思います。そのあたりも任せてつけ忘れを無くしましょう。

```sh
# Fastfile
  lane :tag do
    add_git_tag(prefix: "v",
                postfix: "-RC1",
                build_number: "1.0.0"
                )
    push_git_tags
  end
```

```sh
$ git tag                                                                                                                                                             (git)-[master]
builds/iostag/v1.0.0-RC1
```

# App Store Connectにアップロード
最後はApp Store Connectへのアップロードです。

### deliver
App Store Connectへのアップロードは`deliver`というアクションを使用します。

```shell
$ fastlane deliver init
```

initを行うと、設定用のDeliverfileとメタデータ、スクリーンショット管理用のフォルダ、ファイルが生成されます。

```
fastlane/Deliverfile
fastlane/metadata/
fastlane/screenshots/
```

すでにストアに設定されている場合でもメタデータをダウンロードしてこれます。

```
fastlane deliver download_metadata
```

deliverについては設定がたくさんあるので詳細は[こちら](https://docs.fastlane.tools/actions/deliver/#deliver)をご確認ください。App Store Connectの設定をGitで管理できるのは良いですね。例えば、カテゴリを管理しているファイルの中身は以下のようになります。

```
$ cat fastlane/metadata/primary_category.txt                                                                                                                          (git)-[master]
MZGenre.Games
```

設定を変更したら実行するだけでストアの情報が書き換わります。

```
$ fastlane deliver
```
# まとめ
今回は思いついた面倒なことを紹介しましたが、fastlaneは本当に色々なことを解決してくれます。実際にはCIサービスのWorkflowとして設定を行い、GitHubへの更新をフックして作業を自動化させることが多いです。来年も可能な限り面倒なことをやらないように過ごしていきたいと思います。

[ここ](https://docs.fastlane.tools/plugins/available-plugins/)でfastlaneのプラグインが見れるのですが、みんながどんなサービスを使っているか、何を自動化したいのかが垣間見れて面白いですね。