マンガZERO(iOS)の開発環境の紹介

マンガZERO(iOS)では環境変数をScheme毎に変えてビルドできるようにしています。

この記事では環境変数を変える理由と実際にConfigファイルを使って環境変数を切り替える手段を紹介します。

社内配布限定のアプリを作りたいなどの要望があった場合、この手法ですぐに対応できるようになるのでオススメです。

マンガZERO(iOS)のSchemeの分け方

以下の3パターンに分けてアプリを生成できるようにしています。

  • Debug
    開発時用。開発者以外は触りません。
  • Adhoc
    社内配布用。新機能の使い心地やユーザビリティなどを確かめる際に使われています。
    社内ではFabricのBetaを使用して、配布しています。
  • Store
    公開用。ストアに公開される状態をもつようにしています。
    弊社ではiTunes ConnectのTestflightを使用して最終デバッグをしています。

上記のSchemeで以下の環境変数を分けて使用するようにしています。

  • Bundle Identifier
  • URL Scheme
  • OTHER_SWIFT_FLUG

1つずつ値を説明します。

Bundle Identifer

アプリ固有識別IDになる値です。

この値はユニークでなくてはなりません。また同じIDを持ったアプリは同一アプリとしてデバイスにインストールされてしまいます。

なので、1つのデバイスにStore版とAdhoc版をインストールできるようにBundle Identifierを分けるようにしています。

Bundle Identifierを分けるようになった理由

余談ではありますが、Bundle Identifierを分ける理由を書いておこうと思います。

マンガZERO(iOS)ではユーザーがお気に入りした作品や読書履歴などの情報をRealmに保存するようにしています。

昔はAdhoc版もStore版も同じBundle Identifierだったため、新機能を実装したAdhoc版を入れる前にStore版を削除しなければならない作業が発生していました。
そしてアプリを削除するとRealmのデータも削除されていました。

しかしRealmのマイグレーション処理が正常に行われているかのテストをするためお気に入りなどをする必要があり、テストする前に無駄な作業が毎回発生しておりました。

そのため、Bundle Identifierを分けて別アプリとして扱うことで、アプリの再インストールの必要性がなくなり、アップデートを繰り返せるようになったのでデータが消えることもない状況になってデバッグや確認作業が格段に捗るようになりました。

URL Scheme

こちらもBundle Identifierの影響で別アプリにした結果、分ける必要が発生した値になります。
別アプリや計測時にAdhoc版とStore版が衝突しないように分けました。

OTHER_SWIFT_FLAG

こちらは以下の構文を使えるように分けています。

#if DEBUG
  // Debug Schemeのビルドの時のみ実行したい
#endif

#if DEBUG || ADHOC
  // Store Scheme以外のビルドで実行したい
#endif

主に分けるタイミングは以下になります。

  1. ログ出力
  2. 広告のテスト配信

ログ出力は開発時以外は出力したくないなどの理由で分けています。

広告のテスト配信については開発時には表示されることだけを知れれば良いので、広告側で用意していただいているTestIDを指定したり、デバイスを登録する処理を書いたりしています。

実際に分ける方法

ここからはスクショ等を用いて、実際に分ける処理の書き方を紹介したいと思います。

# 開発環境
Xcode: 8.3.3
Swift: 3.1
iOS Deployment Target: iOS8 ~
Base SDK: Latest iOS (iOS10.3)

上記の環境で作成しています。

GitHubのrepositoryも用意したので、説明がわかりづらかったら直接プロジェクトを開いてください。(そうならないように頑張ります)

設定の紹介の最後にCocoaPodsとの共存方法も書きましたので、合わせてご確認ください。

プロジェクト作成

アプリケーションであれば問題ないと思いますが、今回はSingle View Applicationで作成しました。

ScreenShot1

Configファイルの作成

作成したいディレクトリ(or Group)の上で右クリック > New File… > Other > Configuration Settings File を選択してください。

ScreenShot2

ファイル名は個人的にConfig.[環境].xcconfigという名前にしています。

e.g )
– Debug : Config.Debug.xcconfig
– Adhoc : Config.Adhoc.xcconfig
– Store : Config.Store.xcconfig

ファイル名をConfig.Debug.xcconfigにして生成すると以下のテキストが書かれたファイルが生成されます。

//
//  Config.Debug.xcconfig
//  \(プロジェクト名)
//
//  Created by \(ユーザー名) on \(生成した時間).
//  Copyright © 2017年 \(Author名). All rights reserved.
//

上記と同様にAdhocStore.xcconfigファイルを作成します。

Configファイルの編集

試しにBundle Identifierを環境毎に変えてみたいと思います。

手順は2つあります。

  1. .xcconfigファイルの編集
  2. .xcconfigファイルの指定と反映

xcconfigファイルの編集

DebugAdhocStoreのファイルを以下のように編集します。

// Config.Debug.xcconfig
PRODUCT_BUNDLE_IDENTIFIER=com.example.SampleConfig.debug
// Config.Adhoc.xcconfig
PRODUCT_BUNDLE_IDENTIFIER=com.example.SampleConfig.adhoc
// Config.Store.xcconfig
PRODUCT_BUNDLE_IDENTIFIER=com.example.SampleConfig

PRODUCT_BUNDLE_IDENTIFIER等の文字列の調べ方はのちに紹介します。

xcconfigファイルの指定と反映

projectファイルを指定して、Configurationsに1つAdhocという値を追加します。

ScreenShot3

Releaseの下にあるボタンを押してDuplicate “Release” Configurationを押します。

名前はなんでも良いのですが、わかりやすい環境名にします。

今回はAdhocにしました。

そして以下のようにBased on Configuration Fileを指定します。

ScreenShot4

ここで1度ビルドしてください。(Cmd + B)

以下のようにTargetの左にConfig.Fileのカラムが追加されています。

ScreenShot5

これを値として使用するために、Targetの値を削除してください。

以下のようにフォーカスされている部分がConfig.Fileの列になっていれば大丈夫です。

ScreenShot6

次にSchemeで切り替えできるように設定していきます。

Schemeの生成

Manage Schemes… を選択してください。

ScreenShot7

設定されているScheme一覧が表示されます。

一覧の下にあるを押して、新しいSchemeを作成してください。

ScreenShot8

名前は適当に\(Target名)-\(環境名)にしてみました。

Targetに関しては適切なものを指定してもらえれば問題ないです。

同様の作業で、Debug用のSchemeも作成します。

今回は以下のようにSchemeを作成しました。

ScreenShot9

環境の割り振り

  • SampleConfig : 申請用 (Config.Store.xcconfigを割り当てる)
  • SampleConfig-Adhoc : Adhoc用(Config.Adhoc.xcconfigを割り当てる)
  • SampleConfig-Debug : Debug用(Config.Debug.xcconfigを割り当てる)

各SchemeにConfigを割り当てる

これで値を反映できるようになります。

試しにSampleConfig-AdhocConfig.Adhoc.xcconfigの値が反映されたbuildができるようします。

以下のようにSampleConfig-AdhocSchemeを選択して、Edit Scheme…を押してください。

ScreenShot10

Run > Info > Build Configuration の値をDebugからAdhocに変えてください。

ScreenShot11

この状態でCloseを押して、ビルド(Cmd + B)してみます。

以下のようにBundle IdentifierConfig.Adhoc.xcconfigで指定した値になっていたら成功です。

(1度カラムを移動しないと表示の反映がされないっぽいので、気をつけてください。)

ScreenShot12

同じようにBuild Configrationの値をDebugReleaseに差し替えると値が変わるようになります。

CocoaPodsを使っている場合の指定方法

CocoaPodsConfigファイルを指定して、ビルド依存などを実現しています。

なのでProject > ConfigrationでConfigファイルを指定しているとエラーやワーニングが出てきます。

試しにこのプロジェクトでHimotokiCocoaPodsで使用するようにPodfileを編集してインストールしてみました。

Himotokiはとてもお世話になっていて、Swiftの書き方とかも学んでいるので使わせていただきました。)

以下は使用したPodfileです。

# Podfile
# Uncomment the next line to define a global platform for your project
platform :ios, '8.0'

target 'SampleConfig' do
  # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
  use_frameworks!

  # Pods for SampleConfig
  pod 'Himotoki'

end

以下がログです。

$ bundle exec pod install
Analyzing dependencies
Downloading dependencies
Installing Himotoki (3.0.1)
Generating Pods project
Integrating client project

[!] Please close any current Xcode sessions and use `SampleConfig.xcworkspace` for this project from now on.
Pod installation complete! There is 1 dependency from the Podfile and 1 total pod installed.

[!] CocoaPods did not set the base configuration of your project because your project already has a custom config set. In order for CocoaPods integration to work at all, please either set the base configurations of the target `SampleConfig` to `Pods/Target Support Files/Pods-SampleConfig/Pods-SampleConfig.debug.xcconfig` or include the `Pods/Target Support Files/Pods-SampleConfig/Pods-SampleConfig.debug.xcconfig` in your build configuration (`SampleConfig/Configs/Config.Debug.xcconfig`).

[!] CocoaPods did not set the base configuration of your project because your project already has a custom config set. In order for CocoaPods integration to work at all, please either set the base configurations of the target `SampleConfig` to `Pods/Target Support Files/Pods-SampleConfig/Pods-SampleConfig.release.xcconfig` or include the `Pods/Target Support Files/Pods-SampleConfig/Pods-SampleConfig.release.xcconfig` in your build configuration (`SampleConfig/Configs/Config.Store.xcconfig`).

[!] CocoaPods did not set the base configuration of your project because your project already has a custom config set. In order for CocoaPods integration to work at all, please either set the base configurations of the target `SampleConfig` to `Pods/Target Support Files/Pods-SampleConfig/Pods-SampleConfig.adhoc.xcconfig` or include the `Pods/Target Support Files/Pods-SampleConfig/Pods-SampleConfig.adhoc.xcconfig` in your build configuration (`SampleConfig/Configs/Config.Adhoc.xcconfig`).

1行抜粋して…

please either set the base configurations of the target `SampleConfig` to `Pods/Target Support Files/Pods-SampleConfig/Pods-SampleConfig.adhoc.xcconfig` or include the `Pods/Target Support Files/Pods-SampleConfig/Pods-SampleConfig.adhoc.xcconfig` in your build configuration (`SampleConfig/Configs/Config.Adhoc.xcconfig`).

とあるようにすでにConfigファイルが指定されているから、Pods/Target Support Files/Pods-SampleConfig/Pods-SampleConfig.adhoc.xcconfigに変えるかincludeしてくれと表示されます。

のでincludeします。

試しにConfig.Adhoc.xcconfigincludeしてみます。

#include "Pods/Target Support Files/Pods-SampleConfig/Pods-SampleConfig.adhoc.xcconfig"

PRODUCT_BUNDLE_IDENTIFIER=com.example.SampleConfig.adhoc

この状態でもう1度pod installしてみます。

$ bundle exec pod install
Analyzing dependencies
Downloading dependencies
Using Himotoki (3.0.1)
Generating Pods project
Integrating client project
Pod installation complete! There is 1 dependency from the Podfile and 1 total pod installed.

[!] CocoaPods did not set the base configuration of your project because your project already has a custom config set. In order for CocoaPods integration to work at all, please either set the base configurations of the target `SampleConfig` to `Pods/Target Support Files/Pods-SampleConfig/Pods-SampleConfig.debug.xcconfig` or include the `Pods/Target Support Files/Pods-SampleConfig/Pods-SampleConfig.debug.xcconfig` in your build configuration (`SampleConfig/Configs/Config.Debug.xcconfig`).

[!] CocoaPods did not set the base configuration of your project because your project already has a custom config set. In order for CocoaPods integration to work at all, please either set the base configurations of the target `SampleConfig` to `Pods/Target Support Files/Pods-SampleConfig/Pods-SampleConfig.release.xcconfig` or include the `Pods/Target Support Files/Pods-SampleConfig/Pods-SampleConfig.release.xcconfig` in your build configuration (`SampleConfig/Configs/Config.Store.xcconfig`).

上記のようにAdhocのワーニングが消えました。のでこれを全てに反映してみます。

// Config.Debug.xcconfig
#include "Pods/Target Support Files/Pods-SampleConfig/Pods-SampleConfig.debug.xcconfig"

PRODUCT_BUNDLE_IDENTIFIER=com.example.SampleConfig.debug
// Config.Store.xcconfig

#include "Pods/Target Support Files/Pods-SampleConfig/Pods-SampleConfig.release.xcconfig"

PRODUCT_BUNDLE_IDENTIFIER=com.example.SampleConfig

の状態で再度pod installすると

$ bundle exec pod install
Analyzing dependencies
Downloading dependencies
Using Himotoki (3.0.1)
Generating Pods project
Integrating client project
Pod installation complete! There is 1 dependency from the Podfile and 1 total pod installed.

上記のようにワーニングが無くなります。

Configで操作したい値のKEYの見つけ方

Keyの見つけ方の紹介です。

Projectファイル > Targetの選択 > Build Settings と選択していき、反映させたい値を選択します。

ScreenShot13

すると右にあるwindowのDeclarationの横に書いてある値がKEYになります。

その下にあるValue Typeが指定できる値になります。

例えばOTHER_SWIFT_FLAGSは以下のように指定できます。

// Config.Debug.xcconfig
OTHER_SWIFT_FLAGS = $(inherited) "-D" "DEBUG" "-D" "ADHOC"

$(inherited)は前の状態を引き継ぐって意味があります。

最後に私がxcconfigを設定してからぶち当たった問題と解決方法の紹介をします。

Config周りで起こり得る問題点と解消方法

xcconfigで書いた値が反映されない

ダメな場合は1度プロジェクトをクリーン(Cmd + K)をしてください。

ビルド時に反映されますが、差分ビルドが走る時は値が反映されないことがありました。

Configファイルの値を変えるときはクリーンビルドすることをオススメします。

xcconfigで書いた値が反映されない(その2)

クリーンしてもだめな場合はそもそもBuild SettingsTargetの値が優先されている場合があります。

Project > Build Settins で追加した値がしっかりフォーカスされているか確認してください。

これでうまく値が反映されない場合はそもそもKeyが違う可能性がありますので、xcconfigファイルをご確認ください。

終わりに

この記事のソースコードは以下のレポジトリにまとめました。

開発の環境構築はプロジェクトの開発スピードUpに直結するので、できる限り早く着手したいところです。

特に環境変数周りは手で操作しているとミスして、最悪審査通過後まで気がつかない不安があるので早めにBuildなどの処理時に変わるように修正することをお勧めします。

このように漫画PF事業部はプロジェクトのPDCAを早く回すために自動化処理や環境構築周りに全力で取り組んでおります。

iOSの開発環境構築や自動化処理などに興味がある方が現在苦労している人いましたらぜひお話出来ればと思います!