どんな時に必要?
CocoaPodsベースのプロジェクトでアプリケーションを開発している時で、特に自前のモジュールもpodでパッケージングしている場合に必要になる事があります。
僕の場合は、pod化した自前モジュールをUnitTestしたい時でした。
ビルド方法によってPreprocessor Macroを切り替えたい
サーバサイドのAPIラッパモジュールを例にとって考えてみたいと思います。
サーバサイドには、ステージング環境や本番環境の切り替えが必要な事がよくあります。
また、その切り替え方法にはPreprocessor Macros
を使用するのが一般的だと思います。
達成したい要件は、以下のようにビルド方法によって環境を切り替える事です:
- UnitTestの時は必ずステージング環境でコンパイル
- このモジュールを使用するアプリケーションのワーキングスペースorプロジェクトでは、各ターゲットの設定に従う
Prefix Headerでは上手く出来ない
モジュールをpod化していなければ、普通にUnitTestターゲットのprefix header(*.pch
)内に定義すればいいだけです。
しかしpod化している場合、モジュールはCocoaPodsが自動で生成したプロジェクトでコンパイルされるため、テストターゲットで定義したフラグは効果がありません。
さらに、Podsプロジェクトのprefix headerとかプロジェクトのBuild Settingsで設定しても、pod install
を実行する毎にリセットされてしまいます。
Podfile
のpost_install
でフラグを指定する
Podfile
には、podがインストールされた後のイベントをHookできます。(参考: CocoaPods Guides – Podfile Syntax Reference)
これを使って、モジュールのターゲットのPreprocessor Macrosを変更できます。
Podfile
は以下のように書きます:
workspace 'APIWrapper'
platform :ios, '6.0'
xcodeproj 'Tests/APIWrapper Tests'
target :'APIWrapper Tests', :exclusive => true do
pod 'Kiwi/XCTest'
pod 'APIWrapper', :path => './'
end
# インストール後に実行される処理を記述
post_install do |installer|
POD_TARGET_NAME = "Pods-APIWrapper Tests-APIWrapper"
# 変更したいビルドターゲットを探す
classy_pods_target = installer.project.targets.find{ |target| target.name == POD_TARGET_NAME }
unless classy_pods_target
raise ::Pod::Informative, "Failed to find '" << POD_TARGET_NAME << "' target"
end
# ビルド設定を追加
classy_pods_target.build_configurations.each do |config|
# Debugターゲットのみ変更
if config.name == "Debug"
# Preprocessor Macrosを変更する
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= ['$(inherited)']
# ステージングのフラグを立てる
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] << "STAGING"
end
end
end
これで、UnitTest用ワーキングスペースで、テスト対象のpodモジュールのPreprocessor Macros
を変更できます!
アプリケーション用のワーキングスペースでは、テスト用の設定は全く気にせずにコーディングできます。