LoginSignup
29
29

More than 5 years have passed since last update.

CocoaPodsで、アプリ側のターゲットに複数のPodsターゲットをリンクするときの設定

Last updated at Posted at 2014-08-10

CocoaPodsを使っているとき、アプリ側のターゲットとPodsターゲットが1:1の場合は、特に何も設定せず使用できるのですが、
アプリ側のターゲットとPodsターゲットが1:多の場合は、アプリ側のbuild_configurationsにどれか1つのPodsターゲットの設定しか書き込まれないため、
Podsのターゲットをいくつか分割している場合面倒なことになります。

例えば、下記のような構成にしている場合、

  • global context(targetで囲まれていない箇所)は、アプリ(Dev, AdHoc, Production, Unittest)共通のライブラリをインストール
  • 試験導入的な意味で"Experimental"というtargetを作って、そこにお試しのライブラリをインストール
  • サーバAPIとの通信が必要なアプリで、まだAPIが実装されていないから"Temporary"というtargetを作って、Mock/Stubライブラリを一時的にインストール
  • Unittestだけで使用するライブラリをインストール

1つのアプリターゲットに大して、Podsターゲットが複数存在した場合、ライブラリはすべてインストールされますが、
build_settingsやfontファイルなどのリソースファイルなどは、どれか1つのPodsターゲットのものしか設定しないため
"Experimental"にfontファイルがふくまれていて、それをコピーしなければならないのにも関わらずコピーされないという状況に陥ったりします。

これを解決するには、post_installを利用して、ライブラリインストールが完了した後に、自前でXcodeの設定を書き換えます。

Podfile
require './lib/helpers/pod_app_helper'  # アプリターゲットのxcconfigやリソースファイルコピースクリプトを設定するための処理

platform :ios, '7.0'

APP_TARGGETS = %w[MyApp MyAppAdHoc MyAppProd]
TESTING_TARGETS = %w[MyAppTests MyAppUITests]
ALL_TARGETS = APP_TARGGETS + TESTING_TARGETS

pod_lib_installer = Proc.new do |name, pod_args|
  args = [name.to_s, pod_args].compact
  pod(*args)
end


link_with ALL_TARGETS

# 共通でインストールするライブラリ
pod 'Facebook-iOS-SDK', '3.16.1'
pod 'AFNetworking', '2.3.1'
pod 'SDWebImage', '3.7.1'
pod 'Underscore.m', '~> 0.2.1'
pod 'UICKeyChainStore', '~> 1.0.5'

# AdHocのみでインストールするライブラリ
target "MyAppAdHoc", :exclusive => true do
   pod 'TestFlightSDK', '~> 3.0.2'
end

# お試しで実験的にインストールするライブラリ
target "Experimental", :exclusive => true do
  link_with ALL_TARGETS
  pod 'FontAwesomeKit', '~> 2.1.7'  # ライブラリにFontファイルがふくまれているのでリソースのコピーが必要
end

# サーバ側未実装の部分があって、APIのstub/mockとか一時的に使用するもの
target "Temporary", :exclusive => true do
  link_with APP_TARGETS - %w[MyAppProd]
  pod 'OHHTTPStubs', '~> 3.1.4'
end

test_libs = {
  'TKRGuard' => '~> 1.0.2',
  'OCMock' => '~> 3.0.2',
  'OHHTTPStubs' => '~> 3.1.4'
}

# Unittestで使用するライブラリ
target "MyAppTests", :exclusive => true do
  test_libs.each(&pod_lib_installer)
end

# UITestで使用するライブラリ
target "MyAppUITests", :exclusive => true do
  test_libs.each(&pod_lib_installer)
  pod 'KIF', '~> 3.0'
end

post_install do |installer|
  # Copy Pods Resourcesのスクリプト追加やxcconfig追加の処理を追加
  self.extend(Pod::AppHelper)

  # アプリ側のxcode projectを開く
  Xcodeproj::Project.open(*Dir.glob('*.xcodeproj')).tap do |project|
    project.targets.each do |target|
      # CocoaPodsがどれかひとつPod targetのresourcesをコピーしているdefaultの`Copy Pods resources`は役にたたないので削除
      target.shell_script_build_phases.each do |phase|
        phase.remove_from_project if phase.name == 'Copy Pods Resources'
      end

      # アプリターゲット毎にxcconfigを設定し、使用するPodsターゲットからリソースコピーを実行するスクリプトを作成する
      if target.name == "MyApp"
        pod_target_names = ['', 'Experimental', 'Temporary']
        add_extra_copy_pods_resources(target, pod_target_names)
        config_file_path = 'etc/App-dev.xcconfig'
        replace_project_base_configuration(project, target, config_file_path)
      elsif target.name == "MyAppAdHoc"
        pod_target_names = ['', 'Experimental', 'Temporary', 'MyAppAdHoc']
        add_extra_copy_pods_resources(target, pod_target_names)
        config_file_path = 'etc/App-AdHoc.xcconfig'
        replace_project_base_configuration(project, target, config_file_path)
      elsif target.name == "MyAppProd"
        pod_target_names = ['', 'Experimental']
        add_extra_copy_pods_resources(target, pod_target_names)
        config_file_path = 'etc/App-Prod.xcconfig'
        replace_project_base_configuration(project, target, config_file_path)
      elsif target.name == "MyAppTests"
        pod_target_names = ['', 'Experimental', 'MyAppTests']
        add_extra_copy_pods_resources(target, pod_target_names)
        config_file_path = 'etc/LogicTests.xcconfig'
        replace_project_base_configuration(project, target, config_file_path)
      elsif target.name == "MyAppUITests"
        pod_target_names = ['', 'Experimental', 'MyAppUITests']
        add_extra_copy_pods_resources(target, pod_target_names)
        config_file_path = 'etc/UITests.xcconfig'
        replace_project_base_configuration(project, target, config_file_path)
      end

      # preprocessor macroの設定を追加する場合もここで
      if TESTING_TARGETS.include?(target.name)
        target.build_configurations.each do |config|
          # Define preprocessor
          if config.name == "Debug"
            preprocessor_definitions = config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] || ['$(inherited)']
            preprocessor_definitions = [preprocessor_definitions] unless preprocessor_definitions.instance_of?(Array)
            # #define TESTING 1
            preprocessor_definitions.push('TESTING=1').uniq!

            config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] = preprocessor_definitions
          end
        end
      end
    end

    project.save     # プロジェクトを保存
  end
end
pod_app_helper.rb
module Pod
  module AppHelper
    # PodsディレクトリにあるPodsターゲット毎のリソースコピースクリプトをアプリターゲットに登録
    def add_extra_copy_pods_resources(target, pod_target_names)
      # Appends Extra `Copy Pods resources` to target
      extra_copy_pods_resources = pod_target_names.map {|pod_target_name|
        script_name = pod_target_name.empty? ? "Pods-resources.sh" :"Pods-#{pod_target_name}-resources.sh"
        {
          :script_name => script_name,
          :script_build_phase_title => "Copy Pods Resources(#{script_name})",
          :shell_script => "\"${SRCROOT}/Pods/#{script_name}\""
        }
      }.reject {|phase|
        target.shell_script_build_phases.map {|phase| phase.name }.include?(phase[:script_build_phase_title])
      }
      extra_copy_pods_resources.each do |phase|
        build_phase = target.new_shell_script_build_phase(phase[:script_build_phase_title])
        build_phase.shell_script = phase[:shell_script]
      end
    end

    # Podsターゲット毎に用意されている`Pods-xxxx.xcconfig`をまとめてインクルードしたxcconfigをプロジェクトに登録する
    def replace_project_base_configuration(project, target, config_file_path)
      config_file = project.files.find {|file| file.path == config_file_path } || project.new_file(config_file_path)
      target.build_configurations.each do |config|
        config.base_configuration_reference = config_file
      end
    end

    module_function :add_extra_copy_pods_resources, :replace_project_base_configuration
  end
end
App-dev.xcconfig
#include "Pods/Pods.xcconfig"
#include "Pods/Pods-Experimental.xcconfig"
#include "Pods/Pods-Temporary.xcconfig"
29
29
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
29
29