Fastlane Deliverを使ったAppStoreへのリリース完全自動化奮闘記

#  はじめに

**fastlane [Deliver](http://docs.fastlane.tools/actions/deliver/#review-information-metadata)** を使うと

- Apple審査へのビルド提出
- 審査通過後のApp Storeへの配信

までの完全な自動化を実現できます
そのプロセスを詳しく手順化してみました（網羅した故めちゃ長いです）

無駄な点や、もっと良い方法、間違いなどありましたら
遠慮なくコメントで教えていただけると嬉しいです！

:::note 
下記の自動化は済んでいる想定です

- **[Gym](https://docs.fastlane.tools/actions/gym/)**：ipaファイル作成までのプロセスの自動化
- [**Match**](https://docs.fastlane.tools/actions/match/)：証明書・プロビジョニングプロファイルの共有・同期の自動化
- **[Snapshot](https://docs.fastlane.tools/actions/snapshot/)**：アプリのスクリーンショット生成の自動化
:::

Gym、Matchのセットアップに関してはこの方の記事が大変参考になります
　→ ****[FastlaneとGitlabRunnerでCI/CDパイプラインを構築する](https://qiita.com/ShionKoga/items/47a3b2c084a76aa218cb)****

Snapshotに関しては私のこちらの記事をどうぞ
　→ [**Fastlane Snapshotを使ってスクショ撮影を自動化する**](https://qiita.com/yuta-shoji/items/7870866f16817994f224)

#  目指すところ

:::note
ブラウザでの**たったのワンクリック**も許さず
審査への**ビルド提出** → 審査通過後の**App Storeへの配信** を達成する 🚀
:::

行けるところまで行ってみようということで
ワンクリックも許さず、とことん自動化していきます

※ワンクリックしたら悪だと言っているわけでは全くありません
　とりあえず経験としてやってみたいからやっています笑

#  Deliverの初期化

❶まず`Fastfile`をひと工夫します
　AppleIDを事前に記述しておくと今後Deliverを初期化するときに
　入力を省略できるので便利です
```ruby: fastlane/Fastfile
apple_id("YOUR_APPLE_ID")
```

❷アプリのルートディレクトリに移動して
　下記コマンドを実行して **Deliver** を初期化します

```bash
$ fastlane deliver
```

❸下記のように質問されるので答えます

```bash
# 現在のディレクトリにdeliverの設定が見つかりません。deliverをセットアップしますか？
$ No deliver configuration found in the current directory. Do you want to setup deliver? (y/n)
$ y

# Rubyの代わりにSwiftを使いたいですか？(y/n)
$ Would you like to use Swift instead of Ruby? (y/n)
$ n
```

::: note warn
2つ目の質問は、***Swiftがまだベータ版*** なので、**Ruby**を選びます。
:::


❹Apple IDの入力を求められるのでメアドを入力します
　*※上記❶を行った場合は入力を求められません*

```bash
# この値を尋ねられないようにするには、'username'を使って指定することができる
$ To not be asked about this value, you can specify it using 'username'

$ Your Apple ID Username: YOUR_APPLE_ID
```

下記のように出力されると成功！

```bash
$ Successfully created new Deliverfile at path './fastlane/Deliverfile'
```
___
Deliverの初期化に成功すると、下記ファイルとディレクトリが生成されます

- **metadata**
    App Storeのメタデータを含むディレクトリ
- **screenshots**
    アプリのスクリーンショットが含まれるディレクトリ
- **Deliverfile**
    リソースを設定するファイル。価格や輸出コンプライアンス、アプリ評価や
    Deliver時の審査へのビルド提出・AppStoreへのリリースを
    自動で行うかなどの各種設定を記述する
    

<details><summary>デフォルトで生成されるファイル群はこのようになっています</summary>

```bash
fastlane
		├── metadata
		│       ├── ja
		│       │   ├── apple_tv_privacy_policy.txt
		│       │   ├── description.txt
		│       │   ├── keywords.txt
		│       │   ├── marketing_url.txt
		│       │   ├── name.txt
		│       │   ├── privacy_url.txt
		│       │   ├── promotional_text.txt
		│       │   ├── release_notes.txt
		│       │   ├── subtitle.txt
		│       │   └── support_url.txt
		│       │   
		│       ├── review_information
		│       │   ├── demo_password.txt
		│       │   ├── demo_user.txt
		│       │   ├── email_address.txt
		│       │   ├── first_name.txt
		│       │   ├── last_name.txt
		│       │   ├── notes.txt
		│       │   └── phone_number.txt
		│       │   
		│       ├── copyright.txt
		│       ├── primary_category.txt
		│       ├── primary_first_sub_category.txt
		│       ├── primary_second_sub_category.txt
		│       ├── secondary_category.txt
		│       ├── secondary_first_sub_category.txt
		│       └── secondary_second_sub_category.txt
		│
		└── screenshots
		│
		└── Deliverfile
```
</details>

#  設定の進め方

設定の仕方は大きく分けて**2つ**あります

- **テキストファイル**に記述して設定する
- **Deliverfile**内に記述して設定する

項目によっては、Deliverfile内でしか設定できないものもあるようです

またそれぞれのメリデメもやりながら感じたので、
適宜都合のいい方を採用して記述するのが良さそうです

## ◯テキストファイルに記述して設定するやり方

基本的には `metadata` ディレクトリに生成された各種テキストファイルに
ファイル名に相当する項目を入力すればOKです

:::note
例えば
- description.txt：アプリの概要
- support_url.txt：サポートサイトのURL
:::

デフォルトで生成されない項目のテキストファイルを自分で作成したり
項目によってはjsonファイルで設定を記述することも可能です

✅ メリット：Deliverfileがスッキリする
⛔ デメリット：テキストファイルなので環境変数が使えない


## ◯Deliverfile内に記述して設定するやり方

一方Deliverfile内に記述する方法もあります

:::note 
例えば著作権に関する設定をDeliverfileに記述すると
```ruby: fastlane/Deliverfile
copyright("#{Time.now.year} Taro Yamada")
```
このように、Deliverfileがサポートしている関数を使えるので
日付を年始にいちいち変える必要などがなくなります
:::

✅ メリット：関数や環境変数が使える
⛔ デメリット：記述が多くなってくると可読性が下がる

#  Deliverfile, Textファイル,  jsonをカスタムする

ここからが重要です
ワンクリックもしないためにDeliverfile、各種Textファイル
もしくはjsonファイルに必要な記述を全て網羅していきます

## ◯レビュー情報

> AppleがこのAppにサインインするためのユーザ名とパスワードです。この情報を使用してAppのすべての機能を審査します。ユーザがソーシャルメディアを使ってサインインする場合は、Appleが使用できるアカウント情報を提供してください。審査期間中、認証情報は有効かつアクティブである必要があります。
> 

Apple審査時のためにDeveloperの情報を設定する必要があります

`fatlane deliver` 実行時に生成されたTextファイルを編集していきます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2633746/fe606ce2-b804-8a28-3127-1a0b6baa7d0d.png)
App Store Connect上だとここの情報です
![AppReviewに関する情報.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2633746/62dc09ab-0a1b-eb43-1444-c7cfa4f17d7f.png)

`first_name`, `last_name`, `phone_number`, `email_address`はそれぞれ適宜入力
`notes` はメモなので任意です。

審査時にAppleに伝えたいことがある場合は記入しましょう。
特にデモモードを実装した時などは、デモモードをスタートする手順などを
記入すると良いと思います。

`demo_user`, `demo_password` は、
ユーザー認証のあるアプリで、審査用のデモアカウントを用意している場合
ここの情報を入力します

::: note
**`phone_number`の書き方**

アメリカのAppleに対して提供する情報なので
海外から日本に発信できる形式の電話番号でなければいけません

例）電話番号が **090-XXXX-YYYY**の場合
 　　→ **+81 90 XXXX YYYY**
:::

## ◯Appカテゴリ

> カテゴリは審査の後にApp Storeに表示されます。
> 

App Storeのカテゴリを設定します

`fatlane deliver` 実行時に生成されたTextファイルを編集していきます
下記リンクを参考に、英語表記で入力します

**各カテゴリの詳細**

| 種類 | 意味 | 必須 |
| --- | --- | --- |
| primary_category | メタデータ: プライマリ カテゴリの英語名(例Business: 、Books) | ● |
| secondary_category | メタデータ: 二次カテゴリの英語名(例Business: 、Books) |  |
| primary_first_sub_category | メタデータ: 主要な最初のサブカテゴリの英語名(例Educational: 、Puzzle) |  |
| primary_second_sub_category | メタデータ: 主要な 2 番目のサブカテゴリの英語名(例Educational: 、Puzzle) |  |
| secondary_first_sub_category | メタデータ: 2 番目の最初のサブカテゴリの英語名(例Educational: 、Puzzle) |  |
| secondary_second_sub_category | メタデータ: 2 番目のサブカテゴリの英語名(例Educational: 、Puzzle) |  |


💡 **参考リンク**
**[Deliver Category Reference](https://docs.fastlane.tools/actions/deliver/#reference:~:text=%E5%88%A9%E7%94%A8%E5%8F%AF%E8%83%BD%E3%81%AA%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E3%82%AB%E3%83%86%E3%82%B4%E3%83%AA%E3%81%AA%E3%81%A9%E3%82%92%E8%A1%A8%E7%A4%BA%E3%81%97%E3%81%BE%E3%81%99%E3%80%82)**
**[App store compare categories](https://developer.apple.com/app-store/categories/#:~:text=its%20Endless%20apps.-,Compare%20categories,-Explore%20and%20compare)**

## ◯言語設定

使用可能な言語は下記です

```
ar-SA, ca, cs, da, de-DE, el, en-AU, en-CA, en-GB, en-US, es-ES, es-MX, fi, fr-CA, fr-FR, he, hi, hr, hu, id, it, ja, ko, ms, nl-NL, no, pl, pt-BR, pt-PT, ro, ru, sk, sv, th, tr, uk, vi, zh-Hans, zh-Hant
```

`fastlane deliver` 実行後は、アプリで既にローカライズされている言語の
ディレクトリが生成されます（この記事の場合は`ja` のみ）
例えば英語 `en-US` にも対応させる場合は以下の設定をします

**`Deliverfile`** に下記を追加します
```ruby:fastlane/Deliverfile
languages(['ja', 'en-US'])
```

そして自分で`./fastlane/metadata/en-US` ディレクトリを作成し
その中に各種テキストファイルを作成して入力しましょう　

## ◯****Metadata****

`fastlane deliver` を実行したときに生成される、言語ごとのディレクトリ内には
アプリのメタデータを設定するTextファイル群があります

それぞれの概要は以下です（**[公式doc](https://docs.fastlane.tools/actions/deliver/#:~:text=alias%20for%20%22upload_to_app_store%22-,Parameters,-Key)**）

| ファイル名 | 概要 | 必須 |
| --- | --- | --- |
| apple_tv_privacy_policy.txt | AppleTVのプライバシーポリシーテキスト |  |
| description.txt | アプリの説明 | ● |
| keywords.txt | ヒットさせたい検索のキーワード（1つ以上入力必須） | ● |
| marketing_url.txt | マーケティングURL |  |
| name.txt | アプリの名前 | ● |
| privacy_url.txt | プライバシーURL | ● |
| promotional_text.txt | プロモーションテキスト |  |
| release_notes.txt | このバージョンのリリースノート |  |
| subtitle.txt | アプリのサブタイトル | ● |
| support_url.txt | サポートURL | ● |

該当するものを入力していきます
必須でないものは何もしなくてOKです
言語設定で登録した言語分、それぞれのディレクトリで設定する必要があります

:::note
💡 **support_url**, **privacy_url**に関して
特に該当するサイトがない場合は、自身の**Twitter**や**Facebook**など
**SNS**のリンクでも大丈夫みたいです
:::


:::note 
💡 **Deliver** は [**Default言語**](https://docs.fastlane.tools/actions/deliver/#:~:text=Default%20values,-Deliver%20has%20a) というものをサポートしています
>Deliverには特別なデフォルト言語コードがあり、ローカライズされていない値を指定することができます。
デフォルトを使用するには、アプリが使用する言語を deliver に伝える必要があります。これには、次の2つの方法があります：
メタデータフォルダ内に言語名のフォルダを作成する（fastlane/metadata/ja-USやfastlane/metadata/de-DEなど）。
Deliverfileのlanguages(['en-US','de-DE'])に以下を追加します。
deliverは、Deliverfileとmetadataフォルダの両方の言語セットの結合を取り、有効になる単一の言語セットを作成します。

要は、`ja, en-US, el, it` の複数言語に対応させたい場合
name, keywords, subtitleなどのほとんどの設定項目は共通して英語でいいけど、
`description`だけはそれぞれの国ごとにローカライズして
個別で設定するということができます

ディレクトリ構造で表すとこんな感じです
```
   default
      keywords.txt
      marketing_url.txt
      name.txt
      privacy_url.txt
      support_url.txt
      release_notes.txt
   en-US
      description.txt
   de-DE
      description.txt
   el
      description.txt
   it
      description.txt
```

:::

## ◯ 著作権

> Appの独占権の取得年、所有する人物名または組織名の順で
入力してください
（例：「2008 Acme Inc.」）。URLは含めません。
> 

アプリに関わる著作権情報を記述する必要があります
著作権をあまり意識していないアプリでも、審査には必須のようです
日付（年）と名前を入れます
また、毎年yearを更新したいのであれば下記関数を使うと便利です
今回はこの関数を使いたいので **`Deliverfile`** で設定します

```ruby:fastlane/Deliverfile
copyright("#{Time.now.year} Taro Yamada")
```

## ◯App価格帯

これは **`Deliverfile`** でしか設定できなさそうです
**`Deliverfile`** 内で下記関数に **$ドルの数値** を渡します
無料アプリであれば `0` でOKです

```ruby:fastlane/Deliverfile
price_tier(0)
```

:::note alert
価格の基準となる国または地域を
fastlaneで設定する方法が見つかりませんでした

有料アプリの場合で、基準を日本円にしたい場合は
ブラウザでここを操作する必要があるのかもしれません
![価格.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2633746/0f241225-e379-2d4e-d59f-66651fa473ec.png)
![価格2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2633746/c84c95c1-09ea-1e88-0696-51de970ecb1f.png)
:::

## ◯年齢制限指定

> Appの年齢制限指定はすべてのプラットフォームの
App Storeに表示されます。
[**Deliver doc**](https://docs.fastlane.tools/actions/appstore/#:~:text=or%0Areset_ratings(false)-,app_rating_config_path,-You%20can%20set)
> 
![年齢制限指定1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2633746/752ce1da-3563-7bc6-28ec-9967793c76fc.png)
![年齢制限指定2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2633746/b863bea9-0d91-c552-b932-afc8d6281456.png)
![年齢制限指定3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2633746/72c168b5-7997-8a83-3f72-68aea312c90b.png)

Appleコンテンツの各項目に対して年齢制限の程度を指定します
この項目は 設定項目を`json`ファイルに記述し
`Deliverfile`で参照する必要があります

`fastlane/metadata/` 直下に `app_store_rating_config.json` を追加します

```json:fastlane/metadata/app_store_rating_config.json
{
    "violenceCartoonOrFantasy": "NONE",
    "violenceRealistic": "NONE",
    "violenceRealisticProlongedGraphicOrSadistic": "NONE",
    "profanityOrCrudeHumor": "NONE",
    "matureOrSuggestiveThemes": "NONE",
    "horrorOrFearThemes": "NONE",
    "medicalOrTreatmentInformation": "NONE",
    "alcoholTobaccoOrDrugUseOrReferences": "NONE",
    "gamblingSimulated": "NONE",
    "sexualContentOrNudity": "NONE",
    "sexualContentGraphicAndNudity": "NONE",
    "contests": "NONE",
    "gambling": false,  
    "seventeenPlus": false,
    "unrestrictedWebAccess": false
}
```

<details><summary>各プロパティの意味はこちら</summary>

| プロパティ | 意味 |
| --- | --- |
| violenceCartoonOrFantasy | アニメまたはファンタジーバイオレンス |
| violenceRealistic | リアルな暴力的表現 |
| violenceRealisticProlongedGraphicOrSadistic | 長時間の過激なまたは加虐的でリアルな暴力 |
| profanityOrCrudeHumor | 冒とく的または下品なユーモア |
| matureOrSuggestiveThemes | 成人向けまたは成人向けを暗示するテーマ |
| horrorOrFearThemes | ホラー／恐怖に関するテーマ |
| medicalOrTreatmentInformation | 医療／治療情報 |
| alcoholTobaccoOrDrugUseOrReferences | アルコール、タバコ、ドラッグの使用または言及 |
| gamblingSimulated | 疑似ギャンブル |
| sexualContentOrNudity | 性的内容およびヌード |
| sexualContentGraphicAndNudity | 過激な性的表現およびヌード |
| contests | コンテスト |
| unrestrictedWebAccess | 無制限のWebアクセス |
| gambling | ギャンブル |
| seventeenPlus | 17+に制限 |

</details>

[テンプレートはこちら](https://github.com/fastlane/fastlane/blob/master/deliver/assets/example_rating_config.json)

また、jsonの [Value](https://docs.fastlane.tools/actions/appstore/#reference:~:text=Non%20Boolean-,Values,-0%3A%20None%20(Legacy))にはルールがあります

:::note
**推奨**
なし　　　：　**NONE**
まれ／軽度：　**INFREQUENT_OR_MILD**
頻繁／極度：　**FREQUENT_OR_INTENSE**
:::

:::note alert
**非推奨**
なし　　　：　**0**
まれ／軽度：　**1**
頻繁／極度：　**2**
:::

unrestrictedWebAccess、gambling、seventeenPlusの3つに関しては**真偽値**
それ以外は上記のルールに従って記述してください

---

次に **`Deliverfile`** に下記を追加します

```ruby:fastlane/Deliverfile
app_rating_config_path("./fastlane/metadata/app_store_rating_config.json")
```

## ◯ipaファイルの場所指定

**Gym**によって生成されるipaファイルのパスを指定する必要があります

**`Deliverfile`** に下記を追加します

```ruby:fastlane/Deliverfile
ipa("./fastlane/builds/YOUR_APP_NAME.ipa")
```

## ◯コンテンツ配信権

> あなたのAppがサードパーティ製のコンテンツを含む、表示する、またはそれにアクセスする場合、そのコンテンツに必要な権利を保有しているか、使用を許可されている必要があります。
> 

**[公式doc](https://docs.fastlane.tools/actions/appstore/#reference:~:text=app_review_attachment_file%3A%20%22./readme.txt%22-,submission_information,-Must%20be%20a)**

Appがサードパーティ製のコンテンツを使用しているかや
アプリ内広告を含むかどうかなどの項目です
![コンテンツ配信権.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2633746/7d119432-56be-027d-c74c-fb1f3a214dfc.png)

今回は下記項目を設定しました
もしかしたら必須じゃない項目もあるかもです

| 項目 | 概要 |
| --- | --- |
| content_rights_contains_third_party_content | サードパーティ製コンテンツを含むか |
| export_compliance_uses_encryption | 輸出コンプライアンスの暗号化を使用するか |
| export_compliance_encryption_updated | 輸出コンプライアンスの暗号化を更新するか |
| add_id_info_uses_idfa | 広告ID情報-idfaを使用するか |
| add_id_info_serves_ads | 広告ID情報-広告を配信するか |
| add_id_info_tracks_action | 広告ID情報-アクションの追跡を行うか |
| add_id_info_tracks_install | 広告ID情報-インストールの追跡を行うか |

[**全てのプロパティはこちら**](https://github.com/artsy/eigen/blob/faa02e2746194d8d7c11899474de9c517435eca4/fastlane/Fastfile#L132C5-L132C27)

**`Deliverfile`** に下記を追加します

```ruby:fastlane/Deliverfile
submission_information({
    content_rights_contains_third_party_content: false,
    export_compliance_uses_encryption: false,
    export_compliance_encryption_updated: false,
    add_id_info_uses_idfa: false,
    add_id_info_serves_ads: false,
    add_id_info_tracks_action: false,
    add_id_info_tracks_install: false,
})
```

特に該当しなければこれでOKです

※参考にさせていただいた記事は[**こちら**](https://qiita.com/rc_code/items/0465f983aa09e0fe0b99#deliver%E3%81%8B%E3%82%89%E3%81%AE%E9%80%81%E4%BF%A1:~:text=developer.apple.com-,deliver%E3%81%8B%E3%82%89%E3%81%AE%E9%80%81%E4%BF%A1,-%E3%81%95%E3%81%A6%E3%81%A7%E3%81%AF%E5%AE%9F%E9%9A%9B)です

## ◯App内課金の事前チェック

`fastlane deliver` 実行時
デフォルトではビルドステップで**アップ内課金の事前チェック**が実行されます
これにより、App内課金をサポートしているかどうかに関係なく
ビルドが失敗してしまいます

```bash
$ Precheck cannot check In-app purchases with the App Store Connect
$ API Key (yet). Exclude In-app purchases from precheck, disable 
$ the precheck step in your build step, or use Apple ID login
```

それを解決するために`Deliverfile`に下記を追加します

```ruby:fastlane/Deliverfile
precheck_include_in_app_purchases(false)
```

こうすることでbuild時点でのApp内課金チェックをスキップできます

## ◯アプリを自動的に審査に提出する

このオプションをオンにすると`fastlane deliver` 実行時に
アプリのビルドを自動的にApple審査に提出することができます
オフにするとブラウザで手動で審査に出す設定になります
この記事ではワンクリックも許されないのでオンにします

**`Deliverfile`** に下記を追加してください

```ruby:fastlane/Deliverfile
submit_for_review(true)
```

## ◯アプリを自動的にAppStoreへリリースする

このオプションをオンにするとApple審査通過後
自動でApp Storeにアプリがリリースされます
オフにするとブラウザで手動でリリースする設定になります
言わずもがなこちらもオンにします

**`Deliverfile`** に下記を追加してください

```ruby:fastlane/Deliverfile
automatic_release(true)
```

## ◯アップロード済みのスクショを上書きする（オプション）
新しいスクリーンショットをアップロードする前に
以前にアップロードしたスクリーンショットをすべて消去するかのオプションです
オフにすると以前のスクショに追加される形になります

毎回ブラウザで削除するポチポチ作業が面倒な方はオンにすると便利です

**`Deliverfile`** に下記を追加します
```ruby:fastlane/Deliverfile
overwrite_screenshots(true)
```

## ◯HTMLレポートの検証をスキップする（オプション）

デフォルトでは`fastlane deliver` 実行時に
こんな感じのHTMLレポートがブラウザで起動されます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2633746/eeefd8db-ef20-b9ad-8589-6aa3b7699541.png)

その後コマンドラインで、「reviewこんな感じだけど、このまま進める？」
と聞かれ、yesと答えると処理が継続されます
このオプションをオンにするとこのチェックをスキップできます
設定する場合は **`Deliverfile`** に下記を追加してください

```ruby:fastlane/Deliverfile
force(true)
```

## ◯審査中の場合はキャンセルして上書きする（オプション）

すでに審査に出しているビルドがある場合、
新しいビルドでその審査を上書きするかどうかのオプションです
必要な場合は **`Deliverfile`** に下記を追加してください

```ruby:fastlane/Deliverfile
reject_if_possible(true)
```

#  それ以外にやる必要のあること

Deliverfileや各種テキストファイルだけでは設定が不十分です
それ以外にもいくつかやらいないと完全自動Deliverを達成できないので
その辺も網羅していきます

## ◯Appのプライバシー設定

**[Deliver doc](https://docs.fastlane.tools/actions/deliver/#:~:text=false%2C%20%5C%22add_id_info_uses_idfa%5C%22%3A%20false%20%7D%22-,App%20Privacy%20Details,-Starting%20on%20December)**

> 2020年12月8日より、Appleはデベロッパーにアプリのプライバシー情報を提供することを義務付けると発表しました。
> 

 ****[Uploading App Privacy Details](https://docs.fastlane.tools/uploading-app-privacy-details/)****

> fastlaneには、upload_app_privacy_details_to_app_storeアクションでアプリのプライバシー詳細をアップロードする機能があります。このアクションには2つのステップがあります。1つ目は、インタラクティブなアンケート（App Store Connect dashboardが提供するものに似ています）に回答し、回答をJSON設定ファイルに保存します。2つ目は、アプリのプライバシーに関する回答をApp Store Connectにアップロードすることです。
> 
> 
> このアクションは、設定を保存するJSON設定ファイルをfastlane/app_privacy_details.json（デフォルト）に出力します。このJSONファイルを出力することで、回答をソース管理に保存し、あなたやチームメンバーが確認したり、他のアプリに使用したりすることができます。JSONファイルは、対話式の質問をスキップするために、このアクションで再び使用できます(json_pathオプション付き)。
> 

要はプライバシー情報を提供しないと自動化ができません

今回は **`Fastfile`** に記述し、
ipaファイル作成時に質問に答えてjsonファイルを生成する方法を採用します

❶ **`Fastfile`** に下記を追加します

```ruby:./fastlane/Fastfile
upload_app_privacy_details_to_app_store(
  username: "YOUR_MAIL_ADDRESS",
  team_name: "YOUR_TEAM_NAME",
  app_identifier: "YOUR_BUNDLE_ID",
)
```

❷Fastfile下記のようなレーンがあるか確認してください
　Matchを使った証明書同期を行い、Gymで新しくipaファイルを作成する
　レーンが必要です（今回は`build`というレーン名です）

```ruby:./fastlane/Fastfile
platform :ios do
  desc "Sync certificates"
  lane :sync_certificates do
    match({readonly: true, type: "appstore"})
  end

  desc "Create ipa"
  lane :build do
    sync_certificates
    increment_build_number(build_number: ENV['CI_JOB_ID'])
    gym
  end
end
```

❸ターミナルで下記コマンドを実行します

```bash
$ fastlane build
```

❹するといくつか質問されるので下記のように答えます

```bash
# アプリのデータ使用量を更新するためのJSONファイルが提供されていません。
$ You did not provide a JSON file for updating the app data usages

# fastlaneは、JSONファイルを生成するための対話型質問を実行します。
$ fastlane will now run you through interactive question to generate the JSON file

# このJSONファイルはソースコントロールに保存し、:json_fileオプションを使ってこのアクションで使うことができます。
$ This JSON file can be saved in source control and used in this action with the :json_file option

# 開始しますか?
$ Ready to start? (y/n)
$ y
```

❺データを収集しない場合は「**n**」と答えます

```bash
# データを収集していますか？
$ Are you collecting data? (y/n)
$ n
```

❻するとipaファイルが新しく作成されると同時に
　`fastlane/app_privacy_details.json` が生成されます

　今回はデータを収集しないので下記のような内容になっています

```json:fastlane/app_privacy_details.json
[
  {
    "data_protections": [
      "DATA_NOT_COLLECTED"
    ]
  }
]
```

❼ **`Fastfile`** の記述を変更します
　
　`upload_app_privacy_details_to_app_store`に
　`json_path`というプロパティを追加します
　❻で生成されたjsonファイルのパスを指定します
　
　これを指定しないと、再び`fastlane build`を実行したときに
　既にjsonは生成されているのにもう一度「json作る？」と質問されてしまいます

```diff_ruby:./fastlane/Fastfile
upload_app_privacy_details_to_app_store(
  username: "YOUR_MAIL_ADDRESS",
  team_name: "YOUR_TEAM_NAME",
  app_identifier: "YOUR_BUNDLE_ID",
+ json_path: "fastlane/app_privacy_details.json",
)
```

## ◯Snapfileを編集する

`fastlane deliver` を実行すると `fastlane/screenshots/` ディレクトリが生成されますが
すでに `fastlane snapshot init` を実行している場合は
恐らくルートディレクトリ直下にも `screenshots/` ディレクトリがあるはずです

Deliverを使ってスクショのアップロードも自動化するに当たって、
`fastlane/screenshots/` の方を使っていきたいので
下記のように `Snapfile` を編集してスクショの保存先を変更します

```ruby:fastlane/Snapfile
output_directory("./fastlane/screenshots")
```

ルート直下の方の`screenshots/` ディレクトリは削除しましょう

## ◯エラーハンドリング

### ・事象

`fastlane deliver` 実行時、多分このようなエラーが出ると思います

```bash
# 指定されたエンティティに不明な属性が含まれています - 'startDate' はリソース 'appPrices' の属性ではありません。

$ The provided entity includes an unknown attribute - 'startDate'
$ is not an attribute on the resource 'appPrices’
```

**`Deliverfile`** で設定した `price_tier` で `0` を指定していると
なぜかこのエラーが出てしまうみたいです

### ・解決策

:::note warn
**Homebrew**でfastlaneをインストールしている場合の解決策です
:::
![price_tierエラー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2633746/304028d1-84fb-34db-c768-b93dd751197e.png)
エラーの少し下の方にスクロールすると
下記のようにファイルのパスを表示してくれていると思います

```bash
& /opt/homebrew/Cellar/fastlane/2.214.0/libexec/gems/fastlane-2.214.0/spaceship/lib/spaceship/connect_api/tunes/tunes.rb
```

このファイルを開き、164行目をコメントアウトします

```diff_swift
included << {
  type: "appPrices",
  id: "${price1}",
  attributes: {
+ #    startDate: nil
  },
  relationships: {
    app: {
      data: {
        type: "apps",
        id: app_id
      }
    },
    priceTier: {
      data: {
        type: "appPriceTiers",
        id: app_price_tier_id.to_s
      }
    }
  }
}
```

これでひとまずは解決しますが、根本は解決できていない気がします
fastlaneの仕様の問題だと思うので、早く解決されてほしいです

[**参考リンク**](https://github.com/fastlane/fastlane/issues/21105#issuecomment-1471756530)

# Fastfileにアップロード用のレーンを追加

ついに仕上げです

`Fastfile` に下記レーンを追加してください

```diff_ruby:fastlane/Fastfile
platform :ios do
  desc "Sync certificates"
  lane :sync_certificates do
    match({readonly: true, type: "appstore"})
  end

  desc "Create ipa"
  lane :build do
    sync_certificates
    increment_build_number(build_number: ENV['CI_JOB_ID'])
    gym
  end

+  desc "Upload to App Store"
+  lane :upload do
+    build
+    snapshot
+    deliver
+  end
end
```

いよいよ、下記コマンドを実行して
**Appleへの審査提出→審査通過後のAppStore配信**までを自動で行いましょう！

```bash
$ fastlane upload
```

無事にApple審査へ提出でき、
その後約15時間でAppStoreへの配信に成功しました！🎉🎉🎉
![Deliverフロー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2633746/ed51cb9b-0fad-d126-cd56-66aa259c0652.png)

# ここまでのまとめ

編集したファイルは全体でこんな感じです

<details><summary>Deliverfile</summary>

```ruby:fastlane/Deliverfile
# Language
languages(['ja', 'en-US'])

# Copy right
copyright("#{Time.now.year} Taro Yamada")

# Indicates that its a free app.
price_tier(0)

# Rating config file path
app_rating_config_path("./fastlane/metadata/app_store_rating_config.json")

# ipa file location
ipa("./fastlane/builds/Counter.ipa")

# Answer the questions Apple would present to you upon manually submitting for review
submission_information({
    content_rights_contains_third_party_content: false,
    export_compliance_uses_encryption: false,
    export_compliance_encryption_updated: false,
    add_id_info_uses_idfa: false,
    add_id_info_serves_ads: false,
    add_id_info_tracks_action: false,
    add_id_info_tracks_install: false,
})

# Clear all previously uploaded screenshots before uploading the new ones
overwrite_screenshots(true)

# Skip validation of HTML reports generated upon submission
force(true)

# Skip precheck in app purchases
precheck_include_in_app_purchases(false)

# Cancel and overwrite if application is pending
reject_if_possible(true)

# option to automatically submit the app for review (turned off here)
submit_for_review(true)

# option to automatically submit the app for release (turned off here)
automatic_release(true)
```
</details>
    
<details><summary>Fastfile</summary>

```ruby:fastlane/Fastfile
app_store_connect_api_key()

default_platform(:ios)

upload_app_privacy_details_to_app_store(
  username: "YOUR_MAIL_ADDRESS",
  team_name: "YOUR_TEAM_NAME",
  app_identifier: "YOUR_BUNDLE_ID",
  json_path: "fastlane/app_privacy_details.json",
)

platform :ios do
  desc "Sync certificates"
  lane :sync_certificates do
    match({readonly: true, type: "appstore"})
  end

  desc "Create ipa"
  lane :build do
    sync_certificates
    increment_build_number(build_number: ENV['CI_JOB_ID'])
    gym
  end

  desc "Upload to App Store"
  lane :upload do
    build
    snapshot
    deliver
  end

end
```
</details>

<details><summary>app_store_rating_config.json</summary> 

```json:fastlane/metadata/app_store_rating_config.json
{
    "violenceCartoonOrFantasy": "NONE",
    "violenceRealistic": "NONE",
    "violenceRealisticProlongedGraphicOrSadistic": "NONE",
    "profanityOrCrudeHumor": "NONE",
    "matureOrSuggestiveThemes": "NONE",
    "horrorOrFearThemes": "NONE",
    "medicalOrTreatmentInformation": "NONE",
    "alcoholTobaccoOrDrugUseOrReferences": "NONE",
    "gamblingSimulated": "NONE",
    "sexualContentOrNudity": "NONE",
    "sexualContentGraphicAndNudity": "NONE",
    "contests": "NONE",
    "gambling": false,  
    "seventeenPlus": false,
    "unrestrictedWebAccess": false
}
```
</details>

<details><summary>app_privacy_details.json</summary>    

```json:fastlane/app_privacy_details.json
[
  {
    "data_protections": [
      "DATA_NOT_COLLECTED"
    ]
  }
]
```
</details>

<details><summary>最終的なディレクトリ構造</summary>    

```bash
└── fastlane
    ├── Appfile
    ├── Deliverfile
    ├── Fastfile
    ├── Gymfile
    ├── Matchfile
    ├── Preview.html
    ├── README.md
    ├── Snapfile
    ├── app_privacy_details.json
    ├── builds
    │   ├── YOUR_APP_NAME.app.dSYM.zip
    │   └── YOUR_APP_NAME.ipa
    ├── metadata
    │   ├── app_store_rating_config.json
    │   ├── copyright.txt
    │   ├── en-US
    │   │   ├── apple_tv_privacy_policy.txt
    │   │   ├── description.txt
    │   │   ├── keywords.txt
    │   │   ├── marketing_url.txt
    │   │   ├── name.txt
    │   │   ├── privacy_url.txt
    │   │   ├── promotional_text.txt
    │   │   ├── release_notes.txt
    │   │   ├── subtitle.txt
    │   │   └── support_url.txt
    │   ├── ja
    │   │   ├── apple_tv_privacy_policy.txt
    │   │   ├── description.txt
    │   │   ├── keywords.txt
    │   │   ├── marketing_url.txt
    │   │   ├── name.txt
    │   │   ├── privacy_url.txt
    │   │   ├── promotional_text.txt
    │   │   ├── release_notes.txt
    │   │   ├── subtitle.txt
    │   │   └── support_url.txt
    │   ├── primary_category.txt
    │   ├── primary_first_sub_category.txt
    │   ├── primary_second_sub_category.txt
    │   ├── review_information
    │   │   ├── demo_password.txt
    │   │   ├── demo_user.txt
    │   │   ├── email_address.txt
    │   │   ├── first_name.txt
    │   │   ├── last_name.txt
    │   │   ├── notes.txt
    │   │   └── phone_number.txt
    │   ├── secondary_category.txt
    │   ├── secondary_first_sub_category.txt
    │   └── secondary_second_sub_category.txt
    ├── report.xml
    └── screenshots
        ├── README.txt
        ├── en-US
        ├── ja
        └── screenshots.html
```
</details>

#  おわりに
ワンクリックも許さず、完全な自動化を達成できました！

今回は、無料でデータ収集もしない超ミニマムなアプリで行ったので
これから本格的なアプリを配信する場合は
またプロセスが変わったり増えたりすると思うので
そのときはまた記事にできたらなと思います

これからもスピードを大事にして開発していきたいです

最後まで読んでいただきありがとうございました！

# **主な参考文献**

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

[Uploading App Privacy Details - fastlane docs](https://docs.fastlane.tools/uploading-app-privacy-details/)

[How to build the perfect fastlane pipeline for iOS | Runway](https://www.runway.team/blog/how-to-build-the-perfect-fastlane-pipeline-for-ios)

[fastlaneのdeliverからAppStoreのメタデータ送信する際の留意点 - Qiita](https://qiita.com/rc_code/items/0465f983aa09e0fe0b99#deliverからの送信)

[deliver: The provided entity includes an unknown attribute - 'startDate' is not an attribute on the resource 'appPrices · Issue #21105 · fastlane/fastlane](https://github.com/fastlane/fastlane/issues/21105#issuecomment-1471756530)
[](https://github.com/artsy/eigen/blob/faa02e2746194d8d7c11899474de9c517435eca4/fastlane/Fastfile#L132C5-L132C27)