iOS開発で環境ごとにアイコンやアプリ名、コード等を切り分けるオレオレプラクティス

iOSアプリ開発においてよくある環境ごとにアプリ名やアイコンを切り替える方法をいっつも忘れてググるので備忘録としてまとめてみました

# 前提
環境別
- Develop（開発用サーバ）
- Staging（ステージングサーバ）
- Production（本番サーバ）

状況別
- Debug（デバッグビルド、デバッグ情報などを付与する）
- Release（本番ビルド）

の合計6種類となる組み合わせを前提とします
各自の状況に合わせてここは好みで変更するとよろしです（これで十分なプロダクトが多いと思うけど）

# 分岐させるところ

## Configurations
[PROJECT] -> [Info] -> [Configurations]から以下の6つを作成します
作成時はDebugのものは元からあるDebugスキーマから複製して作成し、ReleaseのものはReleaseスキーマから複製すること

| Configuration名 | 用途 | 運用方針 |
|:-----------------|:------------------|:------------------|
| Develop_Debug　| 個人環境での開発用 | 開発用サーバへアクセスしつつデバッグ情報などを表示させる |
| Develop_Release | 個人環境でのテスト用 | 開発用サーバへアクセスしつつデバッグ情報などは表示させない |
| Staging_Debug　| ステージング環境での開発用 | ステージングサーバへアクセスしつつデバッグ情報などを表示させる |
| Staging_Release | ステージング環境でのテストや社内配布用 | ステージングサーバへアクセスしつつデバッグ情報などは表示させない |
| Production_Debug　| 本番環境でデバッグしたい時に | 本番サーバへアクセスしつつデバッグ情報などを表示させる  |
| Production_Release　| 本番リリース用 | 本番サーバへアクセスしつつデバッグ情報などは表示させない |

<img width="985" alt="スクリーンショット 2017-12-12 22.27.54.png" src="https://qiita-image-store.s3.amazonaws.com/0/129872/7719ab65-b10a-f29b-de1d-07da86c2329d.png">

## Scheme
スキーマは環境別分(今回は3種類)用意します。

| 種類 | 環境割当て |
|:-----------------|:------------------|
| [APP_NAME]_Develop　| develop版 |
| [APP_NAME]_Staging　| staging版 |
| [APP_NAME]_Production | production版 |

<img width="922" alt="スクリーンショット 2017-12-12 22.55.37.png" src="https://qiita-image-store.s3.amazonaws.com/0/129872/39a318c1-3b07-3b8c-f990-c7a0fbd0d9ee.png">

さらにスキーマ編集からRun時はDebug版、Archive時はRelease版を必ず生成するようにしておくことで変更する手間が殆どいらず、リリース版に誤ってデバッグ情報が含まれてしまうなどの事故が防げると思います。

| 種類 | 状況割当て |
|:-----------------|:------------------|
| Run　| debug版 |
| Test | Release版 |
| Profile　| Release版 |
| Analyze　| Debug版 |
| Archive　| Release版 |

<img width="542" alt="スクリーンショット 2017-12-12 22.57.36.png" src="https://qiita-image-store.s3.amazonaws.com/0/129872/9a659ce6-e7eb-b55c-dfb1-ed8d2051edd3.png">

この設定を3つすべてのスキーマに対してそれぞれ行います。
なお、余談ですがスキーマ編集画面ののSharedチェックボックスはつけておくのがおすすめです。Sharedをつけることでリポジトリに含めることができるので、開発PCが変わったときや複数人での開発においてスキーマ設定を共有できるため効果を発揮します

## Product Bundle Identifier
Configuration別にBundle IDを変更して異なるアプリとしてそれぞれ並列にインストールできるようにすると捗ります。
[TARGET] -> [Build Settings] -> [Product Bundle Identifier]からプルダウンを開いてConfiguration別に異なるBundle IDを割り当てます。
特にこだわりがなければSuffix形式にConfiguration名を付与するのがオススメ

| Configuration | Bundle ID |
|:-----------------|:------------------|
| Develop_Debug　| [ORIGINAL_BUNDLE_ID].develop.debug |
| Develop_Release | [ORIGINAL_BUNDLE_ID].develop |
| Staging_Debug　| [ORIGINAL_BUNDLE_ID].staging.debug |
| Staging_Release | [ORIGINAL_BUNDLE_ID].staging |
| Production_Debug　| [ORIGINAL_BUNDLE_ID].debug |
| Production_Release　| [ORIGINAL_BUNDLE_ID] |

<img width="703" alt="スクリーンショット 2017-12-12 22.40.29.png" src="https://qiita-image-store.s3.amazonaws.com/0/129872/1cb6b027-a740-2717-060b-8a81d96460b2.png">

## Product Name
アプリをインストールする際に紛らわしくならないように名前を替えておいたほうがいいでしょう
[TARGET] -> [Build Settings] -> [Product Name]からプルダウンを開いてConfiguration別に異なる名前を割り当てて下さい

<img width="619" alt="スクリーンショット 2017-12-12 22.40.51.png" src="https://qiita-image-store.s3.amazonaws.com/0/129872/edc9bbb8-15ed-a583-1051-30da9124d6e8.png">

## Asset Catalog App Icon Set Name
Product Nameと同様にアプリアイコンも変更するとわかりやすいかもです
[TARGET] -> [Build Settings] -> [Asset Catalog App Icon Set Name]からプルダウンを開いてConfiguration別に異なるアイコンを用意して割り当てて下さい

<img width="968" alt="スクリーンショット 2017-12-12 23.02.05.png" src="https://qiita-image-store.s3.amazonaws.com/0/129872/ac3676fa-a0a0-2441-614c-9b3fe478ff40.png">

アイコンはひと目でStagingやDebugだとわかるものがよいかと。（スクショのはサンプルなのであんまわかりやすくないですがｗ）

<img width="1190" alt="スクリーンショット 2017-12-12 22.50.26.png" src="https://qiita-image-store.s3.amazonaws.com/0/129872/ddb07bea-5f70-b119-1cd8-866e411f6d86.png">

## コード上でのConfigurations別分岐
コード上でConfigurations別に条件分岐する場合はマクロを設定します。
[PROJECT] -> [Build Settings] -> [Other Swift Flags]からプルダウンを開いてConfiguration別に`-D PRODUCTION_RELEASE`等の異なる値を入力しておきます。

| Configuration | 設定値 |
|:-----------------|:------------------|
| Develop_Debug　| -D DEVELOP_DEBUG |
| Develop_Release | -D DEVELOP_RELEASE |
| Staging_Debug　| -D STAGING_DEBUG |
| Staging_Release | -D STAGING_RELEASE |
| Production_Debug　| -D PRODUCTION_DEBUG |
| Production_Release　| -D PRODUCTION_RELEASE |

<img width="683" alt="スクリーンショット 2017-12-12 22.52.54.png" src="https://qiita-image-store.s3.amazonaws.com/0/129872/d3c61e6d-c9c8-b708-f402-8ebb8702f5fd.png">

そしたら以下のような条件分岐を記載したクラスを作ります。

```swift:Environment.swift
class Environment {

    enum FlaverType {
        case develop
        case staging
        case production
    }

  enum BuildType {
        case debug
        case release
    }

    static func getFlaverType() -> FlaverType {
        #if DEVELOP_DEBUG
            return .develop
        #elseif DEVELOP_RELEASE
            return .develop
        #elseif STAGING_DEBUG
            return .staging
        #elseif STAGING_RELEASE
            return .staging
        #elseif PRODUCTION_DEBUG
            return .production
        #elseif PRODUCTION_RELEASE
            return .production
        #endif
    }

    static func getBuildType() -> BuildType {
        #if DEVELOP_DEBUG
            return .debug
        #elseif DEVELOP_RELEASE
            return .release
        #elseif STAGING_DEBUG
            return .debug
        #elseif STAGING_RELEASE
            return .release
        #elseif PRODUCTION_DEBUG
            return .debug
        #elseif PRODUCTION_RELEASE
            return .release
        #endif
    }

}
```
こうしておくことで環境別、状況別にコード分岐させやすくなります。

# Targetは分けてない理由
Targetを分けるとアプリに含めるファイルを分離できたりして便利な面もある分、Build Settingsが2つになり、管理が面倒になるうえ、ぱっと見そのファイルがどのTargetに含まれるのか網羅的にみることができないのでヒューマンエラーの温床になるリスクのほうが高いと判断したためTargetは分けてないです。

ただ、依存関係の整理手段としてTargetを分離したり、コードを共有した別アプリとしてリリースしたりするのにはTarget切り替えは有効だと思います。