LoginSignup
23
17

More than 5 years have passed since last update.

この記事は - スピカ Advent Calendar 2015 - 7日目の記事です。

弊社の アプリ では開発/本番時にどのように環境設定値を切り替えているかを話したいと思います。

はじめに

以前のプロジェクトでは環境変数を pbxproj に定義していたのですが、以下の点で苦労していました。

  • スキーマと変数定義が密接な関係のため、複数の開発環境向けにビルドするなどが大変
  • pbxproj はファイル管理も含んでいるため、一時的に変更したローカルな定義値を間違えて一緒にコミットすることがあった
    • 差分もたくさん出るので、レビュー側も大変になる
  • 秘密鍵などの情報もコミットしていた

そこで今回以下のような構成を採用しました。
まずフローを図示すると以下のような構成になります。

名称未設定ダイアグラム-4.png

dotenv

環境によって変わる変数は .env で管理しています。
中身はキーバリューで記述します。
※ 本来 .env は環境毎にユニークなことが理想ですが、アプリでは同じ環境でデバッグ/リリースビルドを行うため、 .env 内で両方定義してあります。

.env

SOME_SECRET_KEY_RELEASE = "hoge"
SOME_SECRET_KEY_DEBUG = "fugue"

FACEBOOK_APP_ID_RELEASE = "123456"
FACEBOOK_APP_ID_DEBUG = "654321"

.env ファイル自体は秘密鍵などの情報があるため、今のところバージョン管理していません。ただどこにも管理されていないのは困るので Qiita:Team の記事上で管理をしています。

ERB テンプレート

.env は値の羅列のリストになり、どういった使われ方なのかわかりづらいため、必要な箇所で参照するためのテンプレートを用意しています。
ERB テンプレートはバージョン管理し、pbxproj から分離されたので、変更がある際もレビューしやすくなりました。
あわせてテンプレートから実際のファイルを生成する処理を Xcode の Build Phase スクリプトに設定し、常に最新の環境設定になるようにしています。

xcconfig

xcconfig は YAML ベースでテンプレートを用意しています。
YAML の場合、継承関係の表現が可能なため、 xcconfig の定義に適しています。

xcconfig.yaml.erb
Release: &Release
  INFOPLIST_PREPROCESSOR_DEFINITIONS:
  INFOPLIST_PREPROCESS: "YES"
  FACEBOOK_APP_ID: "<%= ENV['FACEBOOK_API_KEY_RELEASE'] %>"

Debug: &Debug
  <<: *Release
  FACEBOOK_APP_ID: "<%= ENV['FACEBOOK_API_KEY_DEBUG'] %>"

  OTHER_SWIFT_FLAGS: -DDEBUG
  • xcconfig の設置場所はプロジェクト設定にあります。

salonbook-ios-app_xcodeproj.png

Env.swift

Swift の場合マクロ経由の値参照できないため、 Env.swift.erb から必要な環境変数を参照します。

Env.swift.erb

import Foundation

public struct _Env_Release {
    /// Facebook APIキー
    public static let FACEBOOK_API_KEY = "<%= ENV['FACEBOOK_API_KEY_RELEASE'] %>"
}

public struct _Env_Debug {
    /// Facebook APIキー
    public static let FACEBOOK_API_KEY = "<%= ENV['FACEBOOK_API_KEY_DEBUG'] %>"
}

#if DEBUG
public typealias Env = _Env_Debug
#else
public typealias Env = _Env_Release
#endif

おわりに

.env を利用することで環境設定値とスキーマを分けて利用することが可能になりました。
※ Jenkins 環境ではジョブごとにそれぞれの環境を向いた .env を注入して、ビルドをしてたりしています。

よろしければ、みなさんはどうしているか等コメント頂ければ幸いです。

付録

変換処理例

Rakefile
def load_xcconfig_yaml()
  erb = File.open("./config/xcconfig.yaml.erb") { |f| ERB.new(f.read) }
  yaml = YAML.load(erb.result(binding))
  yaml.each{ |scheme, map|
    File.open("./config/#{scheme}.xcconfig", "w") do |f|
      if map
        map.delete("<<") if map.key?("<<")
        map.each { |k, v|
          f.puts "#{k} = #{v}"
        }
      end
    end
  }
end

23
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
17