個人開発アプリに Xcode Cloud を導入してみた

この記事は [and factory.inc Advent Calendar 2021](https://qiita.com/advent-calendar/2021/andfactory) 13日目の記事です。
昨日は、@y-okuderaさんの[『FlutterでアクティブなBottomNavigationBarItemがタップされたらトップまでスクロールさせてみる』](https://qiita.com/y-okudera/items/fcb9ed97a8e351e86e6a)でした。

# はじめに
今回は WWDC2021 で発表された [Xcode Cloud](https://developer.apple.com/jp/xcode-cloud/) を個人開発しているアプリ [『クラロワガイド』](https://apps.apple.com/us/app/id1542346138) に導入した際の記事になります。
基本的な部分は [『Xcode Cloud でプロジェクトをビルドしてみる』](https://qiita.com/koogawa/items/74a6c6246930c1673b8d)の記事を参考にしています。
@koogawa さん大変ありがとうございましたmm

# Xcode Cloud を利用できるまで
Xcode Cloud を利用するには AppleDeveloper に登録している必要があり、下記 URL から利用申請を行います。
https://developer.apple.com/xcode-cloud/beta/request/#!/request/status

自分は7月中旬に利用申請をして2,3回 Support 問い合わせを行いましたが、
結果、利用できるようになったのは11月末頃でした。気長に待ちましょう。

# ビルドをしてみる
まずは Xcode Cloud でビルドをできるようにしていきます。
Xcode13以上で `Product -> Xcode Cloud -> Create Workflow...` を選択します。
![スクリーンショット 2021-12-10 15.06.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/457899/baa7d730-ff5d-842f-5db5-3b06581675ee.png)
下記項目を適当に設定しつつ Workflow を作成していきます

- Start Condition
  - ビルドトリガーの設定等 
- Environment
  - Xcode, MacOS の設定
  - 環境変数の設定
- Actions
  - Build, Test, Archive などの指定
- Post-Actions
  - ビルド後に実行したいアクションの設定
      - 例) Slackなどへビルド結果通知

![スクリーンショット 2021-12-10 15.06.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/457899/9ee5b56b-b6d3-3798-5a63-69cd1448dc08.png)
流れに沿って設定ポチポチしていくと最後に Github リポジトリへのアクセス権限が問われるので承認をすれば作成完了です。
![スクリーンショット 2021-12-10 15.16.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/457899/17b04fed-6e54-5c66-fb1f-b8399d4ed3c9.png)
※ただしこれだけでビルドが完了するのは極稀だと思うため、
以降ではビルド成功までにハマったポイントを記します。

# ハマったポイント

### ビルドトリガーのターゲットブランチ指定について
リモートにブランチが存在しているのに `"ブランチ名" may only exist locally. To use...` という Warning が発生
![スクリーンショット 2021-12-12 10.45.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/457899/6eb7be2b-3576-d75a-258c-63ea8b937101.png)
今は解決されていますが、環境構築時は何故か発生していました。(反映とかに時間かかっていた？)
暫定的な解決策としてはスクショにもあるように `branches beginning with "ブランチ名"` で対応しました。
[Configuring Your Xcode Cloud Workflow’s Start Condition](https://developer.apple.com/documentation/xcode/configuring-your-xcode-cloud-workflow-s-start-condition)

### パッケージ類の依存解決
自分の開発環境に合わせて CocoaPods, Carthage, SwiftPM などのパッケージ管理ツールを、Xcode Cloud でも実行できるように設定する必要があります。
具体的には `ci_scripts` ディレクトリを作成して以下3種類のシェルスクリプトをよしなに用意します。

|シェルスクリプト名|トリガー|用途例|
|----|----|----|
|ci_post_clone.sh|git clone後に実行|パッケージ管理ツールのインストール等|
|ci_pre_xcodebuild.sh|XcodeBuild前に実行|コンパイルオプションの指定等|
|ci_post_xcodebuild.sh|XcodeBuild後に実行|ビルド成果物を他サービスにアップロード等|

[Writing Custom Build Scripts](https://developer.apple.com/documentation/xcode/writing-custom-build-scripts)

自分は今回 `ci_post_clone.sh` を用意して Mint や Carthage, Xcodegen のセットアップを行うようにしました。

```shell:ci_scripts/ci_post_clone.sh
#!bin/sh

# Install Mint
brew install mint
mint bootstrap -m ../Mintfile --overwrite y

# Setup Carthage
mint run Carthage carthage bootstrap --platform iOS --cache-builds --use-xcframeworks --project-directory ../

# Generate xcodeproj
mint run xcodegen xcodegen generate -s ../project.yml
```

以下ハマったポイントを抜粋(主にパス指定周り)

- Mintfile のパス指定をちゃんとする。(`-m` オプション付ける)
- Carthage プロジェクトのパス指定をちゃんとする。(`--project-directory` を付ける)
- Xcodegen で `project.yml` のパス指定をちゃんとする。(`-s` オプションを付ける)

※最初は元々用意していた Makefile を `ci_post_clone.sh` から叩くようにしていたが、
上手く行かなかったので結局今の形になりました。

### SwiftPM の依存解決
SwiftPMを使っている方だとこのようなビルドエラーに遭遇するかもしれません。
![スクリーンショット 2021-12-12 10.09.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/457899/7d8e7876-7f75-7cb2-d856-87a18e43fa32.png)
これは Xcodegen と SwiftPM を組み合わせていたため SwiftPM の依存関係ファイルである `Package.resolved` が存在しない(正確には git 管理対象になっていなかった)事が原因でした。

そのため以下 Issue を参考に .gitignore を修正して
`project.xcworkspace/xcshareddata/swiftpm/Package.resolved` を git 管理対象にするように修正。

[Package.resolved isn't versioned; How are deterministic Package versions achieved?](https://github.com/yonaskolb/XcodeGen/issues/743)

### Carthage の `There is no XCFramework found at XXX` 問題
![スクリーンショット 2021-12-12 11.38.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/457899/74c0921c-a0de-2a65-70fd-4a5da1e6664b.png)
これは `Carthage copy-frameworks` のし忘れでした..
新たに `ci_pre_xcodebuild.sh` を追加して解決しました。

```shell:ci_pre_xcodebuild.sh
#!bin/sh

# Carthage copy frameworks
mint run Carthage carthage copy-frameworks
```

ここまで行って9度目の正直でビルド成功しました🎉
![スクリーンショット 2021-12-12 12.12.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/457899/f23370e7-8b16-11ff-557a-efe8a74fd013.png)

# おまけ
### Slack通知
Workflow の設定画面にある `Post-Actions -> Notify` を選択する。
![スクリーンショット 2021-12-12 12.57.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/457899/6fcd0319-8ac0-4a01-08b0-ff8fd220c89e.png)
`Add a Slack channel`の箇所の 「+」 を押して Slack アプリとの連携を行います。
連携後はチャンネルが表示されるので通知先を指定する。

※自分へのDMとして通知する場合は上記設定は不要で AppStoreConnect の自分のアカウントページ画面(=右上のアカウント名からプロフィール編集タップ後の画面)で通知設定すれば良さそうです。
(デフォルトでは AppleID に紐づくメールアドレスに通知が届く設定になっていました)
![スクリーンショット 2021-12-13 10.43.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/457899/0cf96c5a-0d6b-a85c-80db-a99c9238c8dd.png)


#### ハマりポイント
Xcode 上で Workflow の設定が何故か反映されずに再度 Workflows の設定を見ると
Post-Actions の内容が消えていました。。。
仕方なく App Store Connect の Workflow で設定を行いました。
![スクリーンショット 2021-12-12 12.59.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/457899/9fa0ea97-3e74-72d4-64bf-989907bbfdab.png)

### アーカイブしてみる
設定自体はすごく簡単です。
Workflow の Action に `Archive` を選択するだけです。
ただ自分の環境では上記設定だけではビルドは通りませんでした...

ちゃんと原因が分かっていないのですが、 `carthage bootstrap` の処理で Archive 時だけ [Charts](https://github.com/danielgindi/Charts) ライブラリで怪しそうなエラーが出ています。
![スクリーンショット 2021-12-13 17.14.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/457899/e91d1eb3-aa9e-e144-f556-c2b334b2ecd1.png)
その後の XcodeBuild の際に `There is no XCFramework found at XX` が発生して失敗しました。
![スクリーンショット 2021-12-13 17.16.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/457899/9dc8de18-2568-553d-69b6-577849c39809.png)
理由は分かりませんが、 `ci_post_clone.sh` で `carthage update` を追加したら何故か成功できましたが、Archive する度にライブラリのアプデを行うのは良くないので SPM に移行しようか考えています。。。(詳しい方居たら是非ご教授下さいmm)

```shell:ci_scripts/ci_post_clone.sh
#!bin/sh

# Install Mint
brew install mint
mint bootstrap -m ../Mintfile --overwrite y

# Setup Carthage
mint run Carthage carthage bootstrap --platform iOS --cache-builds --use-xcframeworks --project-directory ../
mint run Carthage carthage update --platform iOS --cache-builds --use-xcframeworks --project-directory ../ # 追加

# Generate xcodeproj
mint run xcodegen xcodegen generate -s ../project.yml
```

### AppStore にアップロードしてみる
これは Action の Archive で `TestFlight and AppStore` にチェックを入れれば OK です。
![スクリーンショット 2021-12-13 19.16.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/457899/0e284bdf-9b52-cc09-4316-1fc8c6a29861.png)
自分の環境ではアーカイブまで出来れば App Store へのアップロードも特に問題無く行えました。
これはすごくありがたいですね。

※ただアップロードされたアプリのビルド番号が Xcode Cloud での `CI_BUILD_NUMBER` になっていました。
~~(なのでその辺りはちゃんと設定した方が良さそうではあります。)~~
[ドキュメント](https://developer.apple.com/documentation/xcode/setting-the-next-build-number-for-xcode-cloud-builds)を見る限り、 Xcode Cloud を利用する場合にはどうしようも無さそうです。
![スクリーンショット 2021-12-13 19.34.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/457899/bdbe0637-689a-e905-6380-2a5badaecd3c.png)
![スクリーンショット 2021-12-13 19.35.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/457899/402e2d06-0bf7-7457-d117-7b2d9e031335.png)

# 最後に
全体的に Xcode 上でポチポチ設定出来たので思ったよりは簡単でした。
ただ使用している SDK 周りの設定に少し手こずったので、開発環境によっては楽だったり大変だったりしそうです。

Chartsライブラリの謎エラー ＆ Carthage Update しないとアーカイブ出来ない課題があるので、SwiftPM 化を今後は進めてアップデートして行けたらなと思っています。

【追記】
Chartsライブラリを Carthage から SwiftPM に移行したら謎の carthage update を行わなくてもアーカイブすることが出来ました。

この記事が今後 Xcode Cloud を使う方の一助になれば幸いです。
最後まで読んで頂きありがとうございました。

# 参考文献
[Xcode Cloud でプロジェクトをビルドしてみる](https://qiita.com/koogawa/items/74a6c6246930c1673b8d)
[Xcode Cloud | Apple Developer Documentation](https://developer.apple.com/documentation/Xcode/Xcode-Cloud)