CocoaPodsでFirebaseをmain target以外に入れることができない問題（解決済）

[iGhost](https://itunes.apple.com/jp/app/ighost-%E3%82%AD%E3%83%A3%E3%83%A9%E3%83%81%E3%83%A3%E3%83%83%E3%83%88/id959326282?mt=8)というアプリで @_mono さんと話したことをシェア。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">Firebaseに強いSwiftラヴ🐶くん <a href="https://t.co/Rg8JX3gNwC">https://t.co/Rg8JX3gNwC</a> <a href="https://twitter.com/hashtag/iGhost?src=hash&amp;ref_src=twsrc%5Etfw">#iGhost</a> <a href="https://twitter.com/hashtag/%E3%83%81%E3%83%A3%E3%83%83%E3%83%88%E3%82%A2%E3%83%97%E3%83%AA?src=hash&amp;ref_src=twsrc%5Etfw">#チャットアプリ</a> <a href="https://t.co/Qcen4RZcGh">pic.twitter.com/Qcen4RZcGh</a></p>&mdash; takasek (@takasek) <a href="https://twitter.com/takasek/status/965423799448477697?ref_src=twsrc%5Etfw">2018年2月19日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# やりたいこと

3層アーキテクチャ(Presentation/Domain/Infra)でいうInfra層をembedded frameworkとして分割し、Infra層内にFirestoreを隠蔽したい。
しかし、そこに立ちはだかる問題。

**Firebaseをmain target以外に入れることができない。**

# どういうことかというと、

## (パターン1) Infra.frameworkにのみFirebaseを入れる

Podfileを書きます。

```rb
platform :ios, '11.2'
use_frameworks!

target 'Infra' do
  pod 'Firebase/Core'
  pod 'Firebase/Firestore'
end
```

こうしたところ、ソースコードにて `import Infra` しようとしても `error: missing required module 'Firebase'` と出てビルドできません。

## (パターン2)abstract targetでmainとInfra層どちらにもFirebaseを含める

[Embedded Framework使いこなし術 - Qiita のコメント](https://qiita.com/mono0926/items/e29cd17789fd1d1548aa#comment-6647af913309c54ef058)を参考に、次のようなPodfileを記述。
(アプリのmain target名がAwesomeAppです)

```rb
platform :ios, '11.2'
use_frameworks!

abstract_target '_' do
  pod 'Firebase/Core'
  pod 'Firebase/Firestore'

  target 'AwesomeApp' do
  end

  target 'Infra' do
  end
end
```

すると、実行時にはコンソールログに次のようなエラーが吐き出されます。

> objc[28375]: Class FIRAIdentifiers is implemented in both /Users/XXXX/Library/Developer/Xcode/DerivedData/AwesomeApp-bdyzjyetywwdoscsrzlhepywlttz/Build/Products/Debug-iphonesimulator/Infra.framework/Infra (0x106fba478) and /Users/XXXX/Library/Developer/CoreSimulator/Devices/C8EB6FE1-BD9E-4D95-A39A-9EF9CD4DC572/data/Containers/Bundle/Application/A3B7F562-51BE-4D71-88FD-C585CC6BF8F5/AwesomeApp.app/AwesomeApp (0x105a93348). One of the two will be used. Which one is undefined.

この状態だと、画面遷移時に以下のリンクのようなループが発生しクラッシュしてしまいます。

ios - Infinite loop viewDidAppear on launch - Stack Overflow
https://stackoverflow.com/questions/42086327/infinite-loop-viewdidappear-on-launch/42086899

（無限ループ自体は info.plist の `FirebaseAutomaticScreenReportingEnabled` を NO にすれば解決しますが、それは本質的ではありませんね）

# とりあえずの解決策

**（[真の解決策が判明しました](https://qiita.com/takasek/items/39c28042c4ecef4685ee#%E7%9C%9F%E3%81%AE%E8%A7%A3%E6%B1%BA%E7%AD%96201831%E8%BF%BD%E8%A8%98)）**
~~**:warning: 眉に唾をつけながら読んでください。**~~

~~とりあえずの解決策としては、パターン1・2ともに、~~
~~**main targetのbuild settingsで `Other Linker Flags` に空文字を入れる（inheritさせない）** と動くようになります。~~

![image.png](https://qiita-image-store.s3.amazonaws.com/0/34405/8237a63a-7e3a-dbbf-f938-e9b4d0a7f302.png)

~~ただ、空文字で上書きすると `pod install` 時に以下のような警告が出るのが気になるところですが…。~~

```
[!] The `AwesomeApp [Debug]` target overrides the `OTHER_LDFLAGS` build setting defined in `Pods/Target Support Files/Pods-AwesomeApp/Pods-AwesomeApp.debug.xcconfig'. This can lead to problems with the CocoaPods installation
    - Use the `$(inherited)` flag, or
    - Remove the build settings from the target.

[!] The `AwesomeApp [Release]` target overrides the `OTHER_LDFLAGS` build setting defined in `Pods/Target Support Files/Pods-AwesomeApp/Pods-AwesomeApp.release.xcconfig'. This can lead to problems with the CocoaPods installation
    - Use the `$(inherited)` flag, or
    - Remove the build settings from the target.
```

~~他のライブラリをPodで入れる場合には嵌まりそうなので、リスクを理解した上で自己責任でお試し下さい。~~
~~あるいはもっと適切な対処法がありましたら是非コメントお寄せ下さい。~~

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">Firebaseをmain targetにしか入れられない問題、しょうがないのでprotocolをinfra layerで定義してapplication layer(main target)で実装して注入するって方法しかなかった気がする</p>&mdash; try! JK教師💓 koutalou (@koutalou) <a href="https://twitter.com/koutalou/status/965429341239693313?ref_src=twsrc%5Etfw">2018年2月19日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

~~:thought_balloon: 諦めてこういう正攻法やるほうがいいのかなあ…。~~

# 真の解決策(2018/3/1追記)

機会あって Firebase の人に直接聞いて解決しました。

```rb
platform :ios, '11.2'
use_frameworks!

target 'Infra' do
  pod 'Firebase/Core'
  pod 'Firebase/Firestore'

  target 'AwesomeApp' do
    inherit! :search_paths
  end
end

```

## ポイント1: `inherit! :search_paths`

これまで意味も分からず使っていましたが、意味は以下の通りです。

https://guides.cocoapods.org/syntax/podfile.html#inherit_bang

> ### inherit!
> Sets the inheritance mode for the current target.
> ### Parameters
> ...
> + `:search_paths` The target inherits the search paths of the parent only.

そのまんまですが。
…字面はそのまんまなんですが、本質的には……どういうことなんでしょうね？:thinking: 

## ポイント2: Main targetはInfraのサブターゲットとする

なんで？ 逆じゃないの？ と思ったんですが、よく考えるとこれが正しい。
何故なら、テストターゲットの Podfile の書き方は以下のようになりますよね。（参考: https://guides.cocoapods.org/syntax/podfile.html ）

```rb
target 'Hoge' do

  target 'HogeTests' do
    inherit! :search_paths
    # Pods for testing

  end
end
```

Target Dependencies が `Hoge` ← `HogeTests` という方向になるとき、 `HogeTests` は `Hoge` のサブターゲットです。
であれば、 Target Dependencies が `Infra` ← `AwesomeApp` という方向であるなら、同じように `AwesomeApp` は `Infra` のサブターゲットとなる。
当然の帰結でした。

# 結論

というわけで、よくよく考えるとそうなるよなというところで解決策が落ち着きました。
この記述であれば、先述したような諸問題は起こらず、正しくアプリを機能させることができます。