Xcode Cloudの導入〜App Store Connectへアップロードする手順


## はじめに

本記事では [Xcode Cloud](https://developer.apple.com/xcode-cloud) を使用してCIを構築した際の手順を簡潔に紹介します。
**Xcode Cloudの導入 〜 ビルド成果物をApp Store Connectにアップロード** までの手順を紹介しています。

ちなみに、現時点でのXcode Cloudでは無料で **25時間/月** のビルド時間が利用できるので、おそらく個人で使う分には無料プランで十分だと思います。

<img width="400" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/7e0b2f9c-4422-7612-fbce-6d497f42ac66.png">

## 前提条件

Xcode Cloudを使用するための条件が [公式ドキュメント](https://developer.apple.com/documentation/xcode/requirements-for-using-xcode-cloud)に記載されているので、必須事項を抜粋して記載します。

### Xcode Cloudを使用するための条件

Xcode Cloudを使用するためには、以下の条件を満たしている必要があります。

- Apple Developer Programに登録されている必要があります。
  Apple Developer Programに登録されていない場合は、[Apple Developer Programに登録](https://developer.apple.com/jp/programs/)してください。
- Xcode 14.0.1 以降を使用してください。
  Xcode 14.0.1 は **macOS 12（Monterey）以降** で対応しているOSになるので、Montereyに対応しているMacを使用してください。
- Xcode 設定のアカウントに Apple ID を追加します。
  XcodeでApple Developer Programに登録されているApple IDのアカウントを追加してください。
- App Store Connectにアプリのアプリ レコードがあるか、アプリ レコードを作成するために必要な役割または権限を持っている必要があります。
  App Store Connectにアプリの情報を登録している必要があります。

### バージョン管理

現時点で、Xcode Cloudは以下バージョン管理システムをサポートしています。
いずれかのバージョン管理システムを使用してリポジトリを作成してください。

- Bitbucket Cloud
- GitHub
- GitLab

## Xcode Cloudの設定

### Xcode Cloudをソース管理システムに登録する

筆者はGitHubでリポジトリを管理しているので、GitHubでの設定手順を紹介しています。

Xcodeでプロジェクトを開いて、一番右のメニューから「Cloud」を選択し、「Get Started...」をクリックします。

<img width="200" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/573e804c-b1ba-e964-20f5-d87ece0041ef.png">

ビルド対象とするアプリを選択して「Next」をクリックします。

<img width="400" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/f47c6add-c63e-4a26-ecb1-1cf7613c8363.png">

以下の画面で「Next」をクリックします。

<img width="400" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/9a1d68ec-7e04-f120-7566-ba1921a05749.png">

GitHubのリポジトリへXcode Cloudを登録するための認証を行うので、
「Grant Access」をクリックして認証を行います。

<img width="400" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/13ad156d-d4d4-6c19-b5a7-fab51e9c7817.png">

以下の画面で「GitHubでステップ2を完了」をクリックします。

<img width="400" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/7ed46804-12b3-4da5-46fe-a0a406a8e201.png">

Xcode Cloudをインストールするアカウントを選択します。

<img width="400" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/9fa8910c-cf6e-6ffb-5366-5953289c40de.png">

今回は指定したリポジトリにのみインストールしたいので、「Only select repositories」を選択し、リポジトリを選択します。
リポジトリを選択したら「Save」をクリックして設定を保存します。

<img width="400" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/cae868b9-5102-1e95-6a2b-35415eadd037.png">

Xcode Cloudの設定が完了するので、「Xcodeで続ける」をクリックして、Xcodeに戻ります。

<img width="400" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/8099b228-ec21-48a5-9ca7-88ccf5bee901.png">

正常に終了すると、以下の画面が表示されているので、「Next」をクリックします。

<img width="400" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/2b51911b-30a6-53b3-9b9a-a9dc983a6568.png">

「Complete」をクリックします。

<img width="400" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/0ba3241a-070d-5fca-6649-b8cdb18b7227.png">

ビルドを開始するかどうかを確認する画面が表示されるので、ビルドを行いたいブランチを選択して「Start Build」をクリックします。

<img width="400" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/6c74e52f-7bb4-21f8-fec9-2229e13efcb8.png">

ビルドが開始されるので、ビルドが完了するまで待ちます。

<img width="600" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/b890bf28-faeb-1a22-f14c-aefff7f441c0.png">

ビルドが完了すると、以下の画面のようになります。

<img width="600" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/f4a67b7f-7fac-e955-1eb4-94c3439a45d5.png
">

GitHubの Settings から Integrations の GitHub Apps を確認すると、Xcode Cloudがインストールされていることが確認できます。

<img width="400" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/435938fd-6058-0c80-3e24-fc669f196f5a.png">

### ワークフローの設定

既存のワークフローを右クリックして「Edit Workflow」を選択します。
「Manage Workflows」を選択するとワークフローの一覧画面が表示されます。

<img width="400" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/00119362-4043-61fb-4686-d38f40544063.png">

以下の画面が表示されるので、各項目を入力してワークフローの設定を行います。

#### General

ワークフローの基本情報を設定します。
基本的にはデフォルトの設定で問題ないですが、必要に応じて設定を変更してください。

<img width="600" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/00302690-b798-abde-6d67-d4c9b279f389.png">

| 項目名 | 説明 |
| --- | --- |
| Name | ワークフローの名前を指定する項目です。デフォルトでは「Default」と設定されていますが、特定のビルドパイプラインの識別名を自由に設定できます。|
| Description | ワークフローに関する説明を記載するフィールドです。チームメンバーがこのワークフローの目的や詳細を把握しやすくするための項目ですが、空白にしておくことも可能です。 |
| Restrict Editing   | このオプションを有効にすると、ワークフローの編集をアカウントホルダー、管理者、アプリマネージャーのみに制限します。チームメンバーが誤って変更しないようにするための設定です。 |
| Primary Repository | ワークフローがアクセスするGitリポジトリを指定します。 |
| Project or Workspace | ビルドするプロジェクトまたはワークスペースファイルを指定します。 |

#### Environment

ビルドに使用する環境や環境変数を設定します。
特に指定がない場合は、デフォルトの設定で問題ありません。

<img width="600" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/fabd8d97-6d98-8004-2e73-162160a72f90.png">

| 項目名 | 説明 |
| --- | --- |
| Xcode Version | ビルドに使用するXcodeのバージョンを指定します。 |
| macOS Version | ビルド環境で使用するmacOSのバージョンを指定します。 |
| Environment Variable Value | 環境変数を設定できる項目です。ビルドプロセスに渡したいカスタム環境変数を追加することで、プロジェクトに対して特定の設定を適用できます。 |
| Environment Variable Secret | 環境変数の値をシークレットとしてマスクするオプションです。例えば、APIキーやパスワードなど、機密情報を環境変数に設定したい場合にこのオプションを有効にして、値を非表示にできます。 |

#### Branch Changes

ビルドするブランチやビルドの開始条件などを設定します。
今回は、mainブランチに変更があった場合にビルドを開始するように設定しています。

<img width="600" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/c45d6903-a5c0-caef-92ac-851f2b22687d.png">

| 項目名 | 説明 |
| --- | --- |
| Source Branch | ビルドを開始するブランチを指定します。「Any Branch」を選択すると、すべてのブランチがビルド対象となります。「Custom Branches」を選択して特定のブランチのみを対象にすることもできます。 |
| Files and Folders | ビルドを開始する条件として、ファイルやフォルダの変更に基づくかを設定します。<br />「Start a Build If Any File Changes」は任意のファイル変更があればビルドを開始する設定です。<br />「Custom Conditions」を選択すると、特定のフォルダやファイルの変更があった場合にのみビルドを開始するようにカスタマイズできます。 |
| Options: Auto-cancel Builds | 「Auto-cancel Builds」オプションを有効にすると、同じブランチに対する新しいビルドが開始された際、実行中またはキューに入っている同じ種類のビルドを自動的にキャンセルします。 |

もし、手動でビルドを開始したい場合は、Start Conditionsの右矢印をクリックして「Manual Start」を選択します。
他のStart Conditionsの設定は削除しておいてください。

<img width="400" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/c31d60bc-59c6-c348-0faf-e27f24d6450e.png">

#### Archive - iOS

対象のスキーマと、配信対象の設定をします。
今回は、TestFlightやApp Store Connectにアップロードせずに、生成されたビルド成果物を手動でアップロードするので「None」を選択しています。

<img width="600" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/148981c1-b19a-5196-b1b8-13bf883e8156.png">

| 項目名 | 説明 |
| --- | --- |
| Platform | 対象となるプラットフォームを指定します。 |
| Scheme | ビルドおよびアーカイブの対象となるXcodeスキームを指定します。 |
| Distribution Preparation | ビルドの配布準備を設定します。次の3つのオプションがあります： |
|  &nbsp;&nbsp; None | 配布準備を行わない設定です。ビルドは行われますが、配布には進みません。 |
|  &nbsp;&nbsp; TestFlight (Internal Testing Only) | ビルドをTestFlightで内部テストとして配布する設定です。プルリクエストや開発ブランチでのテストに推奨されます。 |
|  &nbsp;&nbsp; App Store Connect | ビルドをApp Store Connectにアップロードし、全てのテスターや顧客に配布する設定です。リリースブランチでの使用が推奨されます。 |

#### Post Actions

Post Actions ではビルドが完了した後に実行するアクションを設定できます。
今回は特に設定せずに進みます。

<img width="400" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/3fa39395-c23b-49de-eec5-c1b513ca8153.png">

### カスタムスクリプトの設定

[カスタムスクリプト](https://developer.apple.com/documentation/xcode/writing-custom-build-scripts) を設定することで、ビルド前後に任意の処理を実行できます。
Xcode Cloudだけでは対応できない処理を追加する場合に使用します。
今回は筆者がハマったポイントを紹介します。

#### スクリプトを追加する

カスタムスクリプトを実行するために、プロジェクトの直下に `ci_scripts` ディレクトリを作成し、 `ci_post_clone.sh` ファイルを作成します。

<img width="300" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/94954089-fbdf-79f8-72c3-401889d3d5f5.png">

スクリプトファイルに実行権限がないと、Xcode Cloudでスクリプトを実行できないため、以下のコマンドを実行して実行権限を付与します。

```shell
chmod +x ci_scripts/ci_post_clone.sh
```

#### XcodeBuildToolPluginを組み込んだプラグインの署名検証をスキップする

筆者は、 **LicenseList** というパッケージを使用してアプリで使用しているパッケージの一覧を表示しています。この LicenseList には、PrepareLicenseList という **XcodeBuildToolPlugin** を組み込んだプラグインが含まれています。XcodeBuildToolPlugin では外部のプラグインやスクリプトを実行することが可能であり、署名検証を行わないでビルドするとセキュリティ上のリスクがあるため、ビルドエラーとなります。

<img width="400" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/23efcc44-1511-d64f-69ee-9e52aa9947e2.png">

そのため、Xcodeのプラグインの署名検証をスキップする設定を追加する必要があるので、ビルドスクリプトに以下のコマンドを追加します。

```shell
# Xcodeのプラグインの署名検証をスキップ
# ※LicenseList で PrepareLicenseList の検証でエラーが出るためこの設定が必要
defaults write com.apple.dt.Xcode IDESkipPackagePluginFingerprintValidatation -bool YES
```

#### CocoaPodsの依存関係を解決する

Xcode Cloudでは、Swift Package Manager（SPM）の依存関係は自動的に解決されますが、CocoaPodsの依存関係は手動で解決する必要があります。そのため、ビルド前に pod install を実行するためのカスタムスクリプトを追加する必要があります。Xcode Cloudには Homebrew がインストールされているため、まず Homebrew を使って CocoaPods をインストールし、その後 pod install を実行して依存関係を解決します。

```shell
# CocoaPodsをインストール
brew install cocoapods

# CocoaPodsで管理する依存関係をインストール
pod install
```

## ビルド成果物をApp Store Connect にアップロードする

### ビルド成果物をダウンロードする

ビルドが完了すると、ビルド成果物が生成されます。
それぞれの成果物の役割を以下に記載します。

<img width="600" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/621666f6-def5-e071-82c4-9af098289d63.png">

| Artifact名 | 説明 |
| --- | --- |
| Archive for {ターゲット名} on iOS | iOSアプリのアーカイブファイルで、App StoreやTestFlightへ提出するために使用されます。これにはビルドされたバイナリやアセットなどが含まれています。**Xcodeから直接App Store Connectにアップロードする場合、このアーカイブファイルを使用します**。 |
| Logs for {ターゲット名} archive | アーカイブプロセス中に生成されたログファイルです。ビルド中に発生したエラーや警告を確認するのに役立ちます。特にビルドやアーカイブの問題のデバッグに利用されます。 |
| {ターゲット名} {アプリバージョン} ad-hoc | Ad-hoc配布用にビルドされたアプリケーションで、内部テストなどでiOSデバイスに直接インストールして動作確認するために使用されます。 |
| {ターゲット名} {アプリバージョン} app-store | App Store向けにビルドされたバージョンで、Appleの審査やリリースプロセスに使用されます。**Transporterなど他のアプリを使用してApp Store Connectにアップロードする場合、このファイルを使用します**。 |
| {ターゲット名} {アプリバージョン} development | 開発者向けにビルドされたバージョンで、通常は開発中の動作確認やテストに使用されます。開発環境向けの設定が含まれていることが多いです。 |
| XCResult for {ターゲット名} archive | Xcodeのテスト結果ファイルです。テストの実行結果やビルドの詳細な状態を確認できるため、テストに失敗した場合の詳細を分析する際に使用されます。 |

今回は手動でビルド成果物をApp Store Connectにアップロードするため、**Archive for {ターゲット名} on iOS** をダウンロードします。

<img width="400" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/6bf174d2-38c3-d9cb-7c0e-11feef784598.png">

zipファイルがダウンロードされるので、解凍して、.xcarchiveファイルをダブルクリックします。

<img width="400" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/e8ab20fd-235b-744e-6fb2-37c50605d22d.png">

Xcodeが起動し、以下の画面が表示されます。

### バリデーション

「Validate App」をクリックします。

<img width="400" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/912ee062-29de-010b-033a-3658b69f587d.png">

ここで 「Validate」を選択すると、Teamが選択されていないとエラーが発生します。

<img width="400" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/1251825c-7707-dbbc-9180-9487eb57f45a.png">

<img width="400" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/c7d9798c-f92f-9772-b8e4-6a83d39026ea.png">

そのため「Custom」を選択します。

<img width="400" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/412259c6-18e0-5d9a-1457-ac803eb51a5e.png">

任意のTeamを選択します。

<img width="400" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/2e396066-6fdb-43c6-83fb-e2b5c17eca78.png">

デフォルトのまま進めていきます。

<img width="400" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/163d9972-d9f1-2541-2e7e-e0cfb5c5d31d.png">

<img width="400" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/73e9fbb7-284b-6e6a-832e-62a5e64bf94d.png">

「Validate」をクリックして、バリデーションを行います。

<img width="400" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/4353a021-8a7b-2516-60f0-4c7c911056f7.png">

### アップロード

次にアップロードしていきます。
「Distribute App」を選択します。

<img width="400" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/2860522f-d0f4-ac02-a6c0-1841ffc69663.png">

「Custom」を選択します。

<img width="400" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/cdad9b50-1544-9c20-be58-ab57a8be6df0.png">

デフォルトのまま進めていきます。

<img width="400" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/84c7ecfd-d057-deaf-c4cf-2e0cf799e6c5.png">

<img width="400" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/95a6e8f7-e38e-b5b3-67f4-ee2176a2d0b0.png">

任意のTeamを選択します。

<img width="400" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/b9506ba0-a35b-eabb-5a55-b1c4482c0e17.png">

デフォルトのまま進めていきます。

<img width="400" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/3b85baab-c4ea-3bd3-fece-442247209450.png">

<img width="400" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/860492be-0fff-e3db-5414-3dc713154b1a.png">

「Upload」をクリックします。

<img width="400" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087076/c88237d7-2b12-8b87-7d02-606574186067.png">

以上で、Xcode Cloudのビルド成果物をApp Store Connectにアップロードする手順は完了です。

## 参考リンク

- 公式ドキュメント
  - [Xcode Cloud | Apple Developer Documentation](https://developer.apple.com/documentation/Xcode/Xcode-Cloud)
- Xcode Cloud導入
  - [Xcode Cloudを使ってみた！｜U Log SugiyのLife Log](https://ulog.sugiy.com/xcode-cloud/)
- LicensePlistの依存関係解決時のエラー解決方法
  - [【Xcode Cloud】OSS側でプラグイン使用時にCI環境でビルドできない時の対応 #Swift - Qiita](https://qiita.com/Takia/items/7af9c4e10a09f5366c99)
  - [【Xcode Cloud】Run Build Tool Plug-insを追加すると失敗する #Swift - Qiita](https://qiita.com/SNQ-2001/items/e41c264337166f9b293e)