Xcode
iOS
Swift
iOS2Day 18

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  本番リリース用 本番サーバへアクセスしつつデバッグ情報などは表示させない

スクリーンショット 2017-12-12 22.27.54.png

Scheme

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

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

スクリーンショット 2017-12-12 22.55.37.png

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

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

スクリーンショット 2017-12-12 22.57.36.png

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

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]

スクリーンショット 2017-12-12 22.40.29.png

Product Name

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

スクリーンショット 2017-12-12 22.40.51.png

Asset Catalog App Icon Set Name

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

スクリーンショット 2017-12-12 23.02.05.png

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

スクリーンショット 2017-12-12 22.50.26.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

スクリーンショット 2017-12-12 22.52.54.png

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

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切り替えは有効だと思います。