[iOS] Bitrise + fastlane + App Distributionで配布環境を作成

# はじめに
20卒新卒iOSエンジニアとして働き出した @ARATAYOKOYAMA です
現在，新卒研修としてフルリモートでチーム開発を行っています．フロントの成果物は，iOSアプリです．

さて，このご時世ですから直接成果発表を行うことはできません．
そのため，成果物をメンターや人事に触ってもらうためには，配布する必要があります
そこで，Bitrise + fastlane + App Distribution を使用して構築した配布環境をご紹介します

# Workflow
| Develop | App Distribution |
| -------- | -------- |
| <img width="1200" alt="develop" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160590/f22d7be0-0ad6-e8ce-dfbe-92a4bda61b38.png"> | <img width="1200" alt="adhoc.png" (251.9 kB)" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160590/c69047aa-8640-0e70-c669-6a6a16f88eca.png">   |

上記が今回のWorkflowです．内訳はdevelopへのプルリクをトリガーとしたdevelopと，配布を担うApp Distributionの2つです．
これらの大きな違いは，developでテストを行い．App Distributionではテストは行わず配布のみを行うという点です．

# FastFile
```fastlane/Fastfile 
default_platform(:ios)

before_all do
	if is_ci?
		create_keychain(
		name: ENV['MATCH_KEYCHAIN_NAME'],
		password: ENV['MATCH_KEYCHAIN_PASSWORD'],
		default_keychain: true,
		timeout: 1800,
	)
	end
end

platform :ios do
	desc "Run Test"
	lane :test do
		run_tests(
			workspace: "*.xcworkspace",
			devices: ["iPhone 8 Plus"],
			scheme: "*",
			slack_url: "*")
	end
	desc "Run lint autocorrect"
	lane :lint_autocorrect do
		swiftlint(
		mode: :autocorrect,
		format: true,
		executable: './Pods/SwiftLint/swiftlint',
		config_file: '.swiftlint.yml',
		)
	end
	desc "Run linting"
	lane :lint do
		swiftlint(
		executable: './Pods/SwiftLint/swiftlint', 
		mode: :lint,
		config_file: '.swiftlint.yml',
		)
	end
	desc "Update Swiftgen"
	lane :swiftgen do
		sh "cd .. && ./Pods/SwiftGen/bin/swiftgen"
	end
	"cert test"
		lane :adhoc_archive do
			match(type: "adhoc",
			readonly: is_ci)
			gym(export_method: "ad-hoc")
	end
	"cert test"
		lane :app_distribute do
			match(
				type: "adhoc",
				keychain_name: ENV['MATCH_KEYCHAIN_NAME'],
				keychain_password: ENV['MATCH_KEYCHAIN_PASSWORD'],
				readonly: is_ci)
			gym(export_method: "ad-hoc")
			firebase_app_distribution(
            app: "*",
            groups: "*",
            release_notes: last_git_commit[:message],
            firebase_cli_path: "./node_modules/.bin/firebase"
      		)
			slack(message: "development build successfully delivered to App Distribution")
	end
	  error do |ex|
		slack(message: "Workflow was failed !! something went wrong")
	end		
end
```

上記が今回使用しているFastFileです
lintとSwiftGenはローカルの開発PCで叩くことを想定し，TestはPCとBitriseの両方，app_distributeはBitriseのみを想定しています．
adhoc_archiveは，万が一デプロイがうまくできないとき用の保険として書きました．

各laneで使用しているactionは下記のページを参考に構築しました．

## match
- [fastlane match を使用して iOS の証明書管理を行う](https://qiita.com/kotarella1110/items/840af2cf80aaea1fb035)
- [fastlane match を使用した証明書の作成と更新] (https://qiita.com/sooch/items/a55fb84adbdef4b4542b)
- [match] (https://docs.fastlane.tools/actions/match/)

## create_keychain
- [create_keychain](https://docs.fastlane.tools/actions/create_keychain/)

## firebase_app_distribution
- [Bitrise + Firebase App Distribution でiOSアプリを配布してSlackで通知する](https://qiita.com/xxminamixx/items/2d21bdb729d5c5d6717c)
- [Firebase App Distribution](https://firebase.google.com/docs/app-distribution?hl=ja)


# 意識したこと
## 可能な限りfastlaneに任せること
理由は下記の2つです
1. 会社として研修最終日の配布方法が現時点で決まっていないこと
2. 当初CI/CDサービスとして，Bitrise or GithubActions　のどちらになるか決まっていないこと

1つ目の理由についてもう少し説明します．去年までの成果発表では，開発チームの端末を触ってもらう形で行っていたそうです．
しかし，今年はそうは行きません．では，どうやって配布するのか．．．そのドキュメントがどこにもないのです．
そのため，配布手段がどのような形になってもいいように，adhoc_archive などを用意しました．

2つ目の理由についても同様です．詳しくは説明できませんが，どっちを使うことになってもいいような準備をしておくべきだと考えました．

# 技術的チャレンジをしたかったこと
普段の開発では，CI/CDは意識しません．ちょっと試したいなというときに，わざわざ作らないからです．
また，大学時代は資金の関係もあり，使えるサービスに大きな制限がありました．
そのため，今回の研修では1から自分で作ってみよう！と強く思い，構築しました

# トラブルシューティング
*あくまで私の環境に依存します 参考までに*

## create_keychain
ここに悩まされました．具体的には

```
default_keychain: true,
```
これは，作成したkeychainをdefaultのものとするかどうかのオプションです．
これをtrueにしないと，match側で上手く読み込めず苦労しました．
注意点ですが，絶対にPCでこれを実行してはいけません．そのために，is_ci が付いてます．

## match
まずはこれです．

```
keychain_name: ENV['MATCH_KEYCHAIN_NAME'],
keychain_password: ENV['MATCH_KEYCHAIN_PASSWORD'],
```

どのkeychainを使用するのか明確に記載してあげる必要がありました．
この問題は，[CircieCI の Xcode を 8.3 にしたら Gym で ARCHIVE FAILED になる解決方法](https://qiita.com/star__hoshi/items/a57608258e2598fa7d25)を参考に気が付きました.

## gym
続いて，Xcode側の設定です．
automatically manage signingを無効化し，手動て当てるようにしました．
おそおらく，fastlane側から一度無効化してからgymなのかもしれませんが，とりあえず予め手動で割り当てることで解決しました

## Bitrise
Selectsに設定した環境変数をうまく読み込めなくて苦労していました．
原因は，プルリクエスト時にも読み込めるように設定していなかったからです．
こうなるということは，トリガーや開発フローを見直せって話なんですが，今回はこれで．．．

# 最後に
自分で1から作るのは本当に苦労しました．
それでも，pushして配布メールが届いたときは感動しましたし，よりベストプラクティスを目指して行きたいと思っています．
高速化については，[[iOS] Bitriseのキャッシュをできるだけ生かしてCI / CDの高速化を図る](https://qiita.com/Kazuma_Nagano/items/502c1733f1b6da3a9073)を参考にしながら鋭意取り組み中です

## 参考
- [Bitrise公式](https://devcenter.bitrise.io/jp/getting-started/getting-started-with-ios-apps/)
- [Schemeが共有されていないエラー](http://harumi.sakura.ne.jp/wordpress/2019/04/21/bitriseは簡単って聞くけど私はハマりました😇/)
- [!*.xcodeproj/xcshareddata を入れないとSchemeがShareされない](https://gist.github.com/tokorom/5829394)
- [[iOS] fastlaneを導入する手順について](https://dev.classmethod.jp/articles/prepare-for-ios-app-distribution-part-2/)
- [iOSエンジニアならもはや必須になるつつあるfastlaneで自動テストしてみよう](https://qiita.com/tamappe/items/3d2c1e00344aef3082d2)