XcodeでDevelop/Staging/Release環境を上手に切り分ける方法

# はじめに
アプリに限らずだと思いますが、開発・ステージング・本番の３環境で制作が進んでいくケースは多いと思います。

ここでは、私がXcodeでプロジェクトを作成する際に設定する内容をまとめたいと思います。

# 基本的な設定の流れ
## 初期状態
Xcodeでプロジェクトを新規作成すると、Build ConfingurationはDebugとReleaseの２種類が作られます。
![build_first.png](https://qiita-image-store.s3.amazonaws.com/0/116677/7d276de7-da01-be18-c774-1b7790a5112e.png)


## Build Configrationの設定を好みの形に変更する
タイトルの通り、Develop/Staging/Releaseの３つで作成します。
[+]を押して「Debug」を複製する形で「Staging」を作成し、「Debug」はダブルクリックで名称を「Develop」に変更します。
![build_copy.png](https://qiita-image-store.s3.amazonaws.com/0/116677/62823e10-cbd0-538b-3651-cc5761bcd4bc.png)


最終的に、このようにします。
![build_finish.png](https://qiita-image-store.s3.amazonaws.com/0/116677/c988b82a-638f-6691-ee44-cf4c2bd8dd3e.png)


## PROJECT -> Build Settingsの修正

`Apple LLVM 9.0 – Preprocessing` -> `Preprocessor Macros`
<img width="1392" alt="change_Preprocessor_Macros2.png" src="https://qiita-image-store.s3.amazonaws.com/0/116677/2618f943-8222-0ff7-beb7-d41711859bb8.png">


`Swift compiler - Custom Flags` -> `Other Swift Flags`
<img width="1392" alt="change_other_swift_flags2.png" src="https://qiita-image-store.s3.amazonaws.com/0/116677/7e1c112d-b36d-4b63-1d1f-85e92c4a93de.png">


## ソース上で分岐

上記のように設定すると、ソース上から以下のように分岐で切り分けられるようになります。

```swift
class ViewController: UIViewController {
    
    @IBOutlet weak var testLabel: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()

        #if DEVELOP
            self.testLabel.text = "開発中"
        #elseif STAGING
            self.testLabel.text = "確認してください"
        #else
            self.testLabel.text = "本番向けです"
        #endif
    }

}
```

## 設定上で分岐
個人的な好みですが、設定に関する内容はInfo.plistにまとめたいので、`User Defined`で定義して、呼び出す形にしてみます。

### User Definedで各環境ごとの設定を作成
`PROJECT` -> `Build Settings` 上で、[+]を押して、`Add User-Defined Setting`を選択します。
![user_defined_add.png](https://qiita-image-store.s3.amazonaws.com/0/116677/6acbbd0e-1719-7999-a763-f8f0859e55b1.png)

一番下までスクロールすると、User Definedの項目に`NEW_SETTING`が増えているので、リネームして、各環境ごとの値を緑枠の中で設定します。
![user_defined_hogehoge.png](https://qiita-image-store.s3.amazonaws.com/0/116677/6bf8d2eb-ee39-5c86-6023-40046518f7fd.png)


### Info.plistに項目を追加
ソースから呼び出す際のキーを追加し、型は`String`に、Valueには`$(HOGEHOGE)`と設定します。
（今回は型を`String`で設定しましたが、`Number`などでも出来るのかは未検証です）

![info_plist.png](https://qiita-image-store.s3.amazonaws.com/0/116677/4f0d8a6a-a646-62a9-a3ca-0aff84e6b0cd.png)


### ソースから呼び出す
指定したキーで取得できます。

```swift
let hoge = Bundle.main.object(forInfoDictionaryKey: "kHogehoge") as! String
```


## Schemeの設定
ビルドする際に一発で切り替えできるように、Schemeの設定を環境ごとに作ってしまいましょう。

### `Manage Schemes...`を選択
![scheme_manage.png](https://qiita-image-store.s3.amazonaws.com/0/116677/3910b3ee-d6fa-8669-74f0-9b9a209f13ea.png)


### 既存のSchemeを複製
![scheme_dup.png](https://qiita-image-store.s3.amazonaws.com/0/116677/62d3ba81-dae6-c3e0-bf5d-84fbf465c3d1.png)


分かりやすくリネームしたのち、各項目（RunとかTestとか)上にあるBuild Configrationの設定を統一させて、（その他設定を変えたい所があれば適宜変更して）、Closeします。
（必要分繰り返して、全環境分作成します）
![scheme_copy.png](https://qiita-image-store.s3.amazonaws.com/0/116677/eb4107de-8304-19ac-642f-448d4db04862.png)


### ビルド時に切り替え
ビルド時に実行・停止ボタンの右側ですぐ切り替えられるようになりました。
![scheme_finish2.png](https://qiita-image-store.s3.amazonaws.com/0/116677/cc07579e-a82d-c157-9214-307f33b218cd.png)


# 他にも色々切り替えたい

## Bundle Identifier

本番環境のBundle Identifierの後ろに付け加えて、同じ端末へ別アプリとしてインストールできるようにしてみます。

![iphonex.png](https://qiita-image-store.s3.amazonaws.com/0/116677/9be5adb1-e3e5-6f9b-b269-df328c61a873.png)

| 環境 | Bundle Identifier |
|:-----------|:------------|
| 本番 | jp.co.hogehoge.BuildConfigurationSample |
| 開発 | jp.co.hogehoge.BuildConfigurationSample **.develop** |
| ステージング | jp.co.hogehoge.BuildConfigurationSample **.staging** |


### SUFFIXを追加
`User Defined`の項目に`BUNDLE_ID_SUFFIX`を追加します。
![user_defined_bundle_id_suffix.png](https://qiita-image-store.s3.amazonaws.com/0/116677/17a4206f-60b6-463a-52a2-c320607a8cdd.png)


### TARGETS -> Build Settingsの修正
`Packaging` -> `Product Bundle Identifier`の共通設定の部分を開き、現在設定されているBundle Identifierの後ろに`${BUNDLE_ID_SUFFIX}`を追記します。
![xcode_bundle_id_suffix.png](https://qiita-image-store.s3.amazonaws.com/0/116677/305dba5e-ee0f-b848-623c-f2e2ec1b6cf8.png)



## アプリのアイコン
ホーム画面で表示されるアイコンを変更します。
（Bundle Identifierで使用した`BUNDLE_ID_SUFFIX`を使う前提で書かれています）
![iphonex_icon.png](https://qiita-image-store.s3.amazonaws.com/0/116677/d4325f5e-03b8-6373-6706-0d7ed4a34632.png)


### Assets.xcassetsに各アイコンを準備
標準だと`AppIcon`一つだけなので、複製して`AppIcon.develop`と`AppIcon.staging`を作成し、それぞれにアイコンを設定します。
<img width="539" alt="appicon_assets.png" src="https://qiita-image-store.s3.amazonaws.com/0/116677/9c12f9dd-9ca5-5281-18fd-c95e05eec915.png">


### TARGETS -> Build Settingsの修正
`Asset Catalog Compiler - Options` -> `Asset Catalog App Icon Set Name`の共通設定の部分を開き、現在設定されている`AppIcon`の後ろに`${BUNDLE_ID_SUFFIX}`を追記します。
![appicon_editing.png](https://qiita-image-store.s3.amazonaws.com/0/116677/10cef185-b423-958e-5ffb-777f71c29984.png)


## アプリ名
ホーム画面でアイコン下に表示されるアプリ名を変更します。
![iphonex_app_name.png](https://qiita-image-store.s3.amazonaws.com/0/116677/0efcab1a-5b91-e5d0-bd9f-092a75417f8d.png)


### PREFIXを追加
アプリ名の表示領域はかなり短い（全角7文字程度？）ので、頭に「D」やら「S」やらをつけるだけに留めています。
Bundle Identifierと同様に、`User Defined`の項目に`PRODUCT_NAME_PREFIX`を追加します。
![user_defined_product_name_prefix.png](https://qiita-image-store.s3.amazonaws.com/0/116677/87393b03-66e9-142a-45cb-338ac501db10.png)


### TARGETS -> Build Settingsの修正
`Packaging` -> `Product Name`の共通設定の部分を開き、現在設定されている名前の頭に`${PRODUCT_NAME_PREFIX}`を追記します。
![xcode_product_name.png](https://qiita-image-store.s3.amazonaws.com/0/116677/e20b9dba-8b5d-2d62-565f-a6efb18c20fc.png)

## 外部サービスの設定ファイル

Firebaseの`GoogleService-Info.plist`や、AWSの`awsconfiguration.json`など、外部サービスを使う際に設置を求められる設定ファイルを管理する方法です。

AWSの`awsconfiguration.json`を例に説明します。

### とりあえずの保存場所に置いておく

リネームするかフォルダで分けるかは好みですが、環境別の設定ファイルを用意します。

```
├── {PROJECT_NAME}
│   ├── AWS
│   │   └── configuration
│   │       ├── awsconfiguration-debug.json
│   │       └── awsconfiguration-release.json
```


### Build Phaseで実行されるスクリプトを書く

TARGETS > Build Phasesで、Script Phaseを用意します。

![hoge.png](https://qiita-image-store.s3.amazonaws.com/0/116677/b82642a3-40a6-2cba-191d-4ee984031b5d.png)

shellを書く黒い欄に、以下のコードを記述します。
（保存場所やファイル名は適宜変更してください）

```shell
if [ "${CONFIGURATION}" == "Release" ]; then
cp "${PROJECT_DIR}/${PROJECT_NAME}/AWS/configuration/awsconfiguration-release.json" "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/awsconfiguration.json"
echo "Production awsconfiguration copied."
else
cp "${PROJECT_DIR}/${PROJECT_NAME}/AWS/configuration/awsconfiguration-debug.json" "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/awsconfiguration.json"
echo "Development awsconfiguration copied."
fi
```

あとは、schemeを切り替えてビルドすると、環境別の設定ファイルが本来のファイル名であるべき場所にコピーされます。


# おわりに
GitHubに上げました。（設定ファイルの切り替え例は含まれません）
https://github.com/Todate/BuildConfigurationSample