iOS開発において、環境別にアプリ名やアイコンを変えたり、APIの向き先やログの出力先を変えたりすることが多いですよね。
そういう場合にどう切り分けていくのかの方法を説明します。
準備と基本設定
準備
まずはサンプルのプロジェクトを作成します。

Single View Appで問題ないです。
ここではどれだろうとあまり関係ないのでプロジェクトが作成できれば大丈夫です。
モグモグさん
基本設定
初期の設定でConfigurationsはDebugとReleaseというものがあります。

まずは、このConfigurationsに本番前の環境用ということでStagingを追加していきましょう。
ここではDebugを開発用、Stagingを本番前の環境用、Releaseを本番用としましょう。
Duplicate "Debug" Configuration
を押してStagingを作成します。

作成後はこのようになっていればOKです。

続いてBuild Settings
を設定していきます。
下の画像のように Active Compilation Conditions
と検索します。

Stagingの箇所を、STAGINGに書き換えます。

この段階で、ソースコード上で環境ごと条件分岐ができるようになります。
#if DEBUG
print("Hello, World! from DEBUG env!")
#elseif STAGING
print("Hello, World! from STAGING env!")
#else
print("Hello, World! from RELEASE env!")
#endif
続いてSchemeの設定をしていきます。
Manage schemes
を選択して設定画面を表示します。

初期設定のScheme
をDuplicateしてコピーします。

任意でSchemeの名前を決めて、Build Configurationを作成したStagingに変更します。

同様にReleaseのバージョンも作成していきます。
すると、ビルド時にSchemeを選択できるようになりますね。
env-sample-appが開発用、Staging_Buildが本番前の環境用、Release_Buildが本番用になります。
モグモグさん

それぞれの環境でビルドすると環境を切り替えることができます。
上で書いたこのコードがそれぞれの環境で動くようになります。
#if DEBUG
print("Hello, World! from DEBUG env!")
#elseif STAGING
print("Hello, World! from STAGING env!")
#else
print("Hello, World! from RELEASE env!")
#endif
ここまでで環境に応じて、処理を切り分けられるようになったので具体的によくあるケースに対応できるようにしていきましょう。
アプリ名を環境ごとに分ける
アプリ名を分けるには、User-Defined
を追加していきます。
Levelsの右のプラスボタンを押して、Add User-Defined Settingを押します。

すると下の画像のようにUser-Definedの箇所に設定が一つ追加されるので
SAMPLE_DISPLAY_NAME_PREFIX
としてDebugではDEBUG、StagingではSTAGINGという値を設定してください。
設定完了したものが下の画像になります。
モグモグさん

設定が完了したら、TARGETS
を選択してproduct name
と検索し
値を下の画像のように${SAMPLE_DISPLAY_NAME_PREFIX}-$(TARGET_NAME)
としてください。
そうすると、それぞれの環境でSTAGING-env-sample-app
のようにアプリ名が変更されます。

シュミレーターで、Stagingのschemeで実行するとこのようにアプリ名が変更されています。
Bundle Identifierを環境ごとに分ける
続いてBundle Identifierを環境ごとに分ける方法について説明します。
アプリ名を分ける方法とほとんど一緒になります。
モグモグさん
まずは、User-Definedを追加していきましょう。
手順はアプリ名の時と同様です。
SAMPLE_BUNDLE_PREFIX
という名前で環境ごとに設定しました。
Releaseは既存のままにしたいのでそのままにしています。

続いて定義したUser-Definedの値を利用してBundle Identifierを環境ごとに切り替わるようにしていきます。
TARGETS
でbundle
と検索するとProduct Bundle Identifier
が存在しているのでenv-sample-app.env-sample-app${SAMPLE_BUNDLE_PREFIX}
としてあげます。
${SAMPLE_BUNDLE_PREFIX}の前の部分は、皆さんそれぞれのものになっているので合わせなくて大丈夫です。

すると、それぞれの環境のBundle Identifierが変わっているのが確認できると思います。
一度それぞれのSchemeでビルドをしてみましょう。
Bundle Identifierが切り替わっているので別々のアプリとしてされているのがわかりますね。
環境変数を利用する
基本設定の箇所では、コード上で条件分岐を行なって処理を分けていましたがUser-Definedを利用すれば条件分岐を記述せずに環境ごとの変数を利用できます。
例としてAPIのURLを環境ごとに分けるケースで説明します。
まずはアプリ名やBundle Identifierを切り替えた時と同様にUser-Definedを追加しましょう。
今回は、API_HOST_URL
としました。
値はそれぞれの環境で変更しています。

続いて、今回はinfo.plist
で定義したUser-Definedとマッピングしていきます。
info.plistを選択し、Information Property List
の右側にフォーカスを当てるとプラスボタンが表示されるので、押したのちにKeyをapi_host_url
に設定して、Valueを${API_HOST_URL}
のように先ほど定義した値に変更します。

これで環境変数の設定は完了したのでコード上で呼び出してみます。
下のコードのように呼び出せるので、皆さんの環境でコードを書きSchemeごとにビルドするとログにそれぞれの環境ごとのAPIのURLが表示されていると思います。
let apiHost = Bundle.main.object(forInfoDictionaryKey: "api_host_url") as! String
print(apiHost)
こちらのやり方の方が条件分岐を書く必要がないのでよりシンプルにできますね。