Firebase iOS SDKをSwift Package Managerでいれてみた

Diverse Advent Calendar 2020、24日目の記事になります。

明日はいよいよクリスマスですね！ :christmas_tree:

さて、firebase-ios-sdk は、公式ドキュメント上で CocoaPods からインストールする方法が主に記載されてますが、6.31.0から Swift Package Manager（以下、SPM）での導入もbetaでサポートされてます。

今回は、[README](https://github.com/firebase/firebase-ios-sdk/blob/master/SwiftPackageManager.md) に沿って、firebase-ios-sdk をCocoaPodsからSPMに移行する際につまづいたところを紹介しようと思います。

# 環境

・Xcode 12.3
・firebase-ios-sdk 7.3.1

# FirebaseCrashlytics[^1]

公式ドキュメントに記載されてるCocoaPods利用時の設定は[こちら](https://firebase.google.com/docs/crashlytics/get-started?hl=ja)

Build Phasesに追加してたスクリプトです。

```bash
"${PODS_ROOT}/FirebaseCrashlytics/run"
```

SPMでは、以下の場所にライブラリのソースが配置されます。

```bash
/Users/<user>/Library/Developer/Xcode/DerivedData/<App-hash>/SourcePackages/checkouts/
```


```bash
/Users/<user>/Library/Developer/Xcode/DerivedData/<App-hash>/SourcePackages/
```

このパスは`BUILD_DIR`で取得できますが、DebugビルドとReleaseビルド(Archive)でこの値が変わります。

```bash
# Debug
BUILD_DIR=/Users/<user>/Library/Developer/Xcode/DerivedData/<App-hash>
# Release
BUILD_DIR=/Users/<user>/Library/Developer/Xcode/DerivedData/<App-hash>/Build/Products
```

そのため、Build Phasesのスクリプトでは以下のように設定しました。

```bash
APP_BUILD_DIR=$(dirname $(dirname $BUILD_DIR))

if [ "${CONFIGURATION}" == "Debug" ]; then
    SPM_PATH="."
else
    SPM_PATH="../../.."
fi

"${APP_BUILD_DIR}/${SPM_PATH}/SourcePackages/checkouts/firebase-ios-sdk/Crashlytics/run"
```

### おまけ

CIなどで、firebase-ios-sdk に内包されている `upload-symbols` を使ってarchive後のdSYMをアップロードしたい場合、

CocoaPods では、ライブラリのソースがPods配下に入るので、以下のように実行できました。

```bash
./Pods/FirebaseCrashlytics/upload-symbols -gsp /path/to/GoogleService-Info.plist -p ios /path/to/dSYMs
```

しかしSPMの場合、`BUILD_DIR` のPATHを知る必要がありますが、ビルドプロセス終了後参照できなくなるため、Build Phases中にシンボリックリンクも作成して、archive後に実行できるようにしました。

```bash
# シンボリックリンク作成
ln -s "${APP_BUILD_DIR}/${SPM_PATH}" "spm"

# dSYMアップロード
./spm/SourcePackages/checkouts/firebase-ios-sdk/Crashlytics/upload-symbols -gsp /path/to/GoogleService-Info.plist -p ios /path/to/dSYMs
```

公式ドキュメントは[こちら](https://firebase.google.com/docs/crashlytics/get-deobfuscated-reports?hl=ja&platform=iOS)


# FirebaseAnalytics[^2]

FirebaseAnalyticsをいれていると、IPA作成時に以下のエラーがでます。

![ダウンロード (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139890/cd67bf90-058b-384a-dfc7-6b506811673c.png)


```bash:T/[App]_2020-12-124_00-00-00.000.xcdistributionlogs/IDEDistribution.standard
2020-12-24 00:00:00 +0000  Assertion failed: Expected 2 archs in otool output:
Archive : /var/folders/l9/gkg51h2n0gq224sx06z06t48d5y9wm/T/IDEDistributionOptionThinning.~~~FS4Ibi/Payload/xxx.app/Frameworks/FirebaseAnalytics.framework/FirebaseAnalytics (architecture armv7)
...
Archive : /var/folders/l9/gkg51h2n0gq224sx06z06t48d5y9wm/T/IDEDistributionOptionThinning.~~~FS4Ibi/Payload/xxx.app/Frameworks/FirebaseAnalytics.framework/FirebaseAnalytics (architecture arm64)
...
```

こちらのworkaroundは [README](https://github.com/firebase/firebase-ios-sdk/blob/master/SwiftPackageManager.md)にも記載されていて、以下の３つのFrameworkを削除するスクリプトを、Release Configuration > Build > Post-actionsに追加します。

![93517923-f3827f80-f8e0-11ea-8789-ac721a7a307e.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139890/be7c245c-8614-acef-b9b0-728a01f45939.png)

:point_down: スクリプト部を書き出したもの。

```bash
rm -rf "${TARGET_BUILD_DIR}/${TARGET_NAME}.app/Frameworks/FirebaseAnalytics.framework"
rm -rf "${TARGET_BUILD_DIR}/${TARGET_NAME}.app/Frameworks/GoogleAppMeasurement.framework"
rm -rf "${TARGET_BUILD_DIR}/${TARGET_NAME}.app/Frameworks/FIRAnalyticsConnector.framework"
```


### おまけ

FirebaseAnalyticsをEmbedded Framework上で使ってる場合、削除対象のパスが変わるため、以下のようになります。

```bash
rm -rf "${TARGET_BUILD_DIR}/${TARGET_NAME}.app/Frameworks/<Target>/Frameworks/FirebaseAnalytics.framework"
rm -rf "${TARGET_BUILD_DIR}/${TARGET_NAME}.app/Frameworks/<Target>/Frameworks/GoogleAppMeasurement.framework"
rm -rf "${TARGET_BUILD_DIR}/${TARGET_NAME}.app/Frameworks/<Target>/Frameworks/FIRAnalyticsConnector.framework"
```

※Target: 利用しているEmbedded Framework名


# 最後に

いかがでしたでしょうか。

今回、私の携わってるプロジェクトでは、firebase-ios-sdkをCocoaPodsで使用していましたが、6系から7系に上げる際にRemote Configのfetchのコールバックが呼ばれない問題[^5]に遭遇してしまい、SPM版に移行したところ無事改善することができました。

firebase-ios-sdkは7.3.1からCarthageのサポートが外れ、SPMとCocoaPodsの２つのサポートのみになりましたが、今後SPMサポートしたライブラリがより一層増えていきそうですね！

明日は、 @huma_shaikh さんです。 メリークリスマス！ :christmas_tree:


[^1]: FirebaseCrashlyticsの設定で参考にしたもの
  - [#6864](https://github.com/firebase/firebase-ios-sdk/issues/6864)
  - [Stack Overflow](https://stackoverflow.com/questions/64598321/how-to-access-my-app-s-derived-data-folder-itself)
  - [Medium](https://medium.com/dev-genius/firebase-spm-xcode-12-bcefcef2bd6b)


[^2]: FirebaseAnalyticsの設定で参考にしたもの
  - [#6472](https://github.com/firebase/firebase-ios-sdk/issues/6472#issuecomment-694449182)
  - [#6726](https://github.com/firebase/firebase-ios-sdk/issues/6726)


[^5]: いくつか関連Issueはみつけたものの、私の環境では改善されませんでした:sob:
  - [#3818](https://github.com/firebase/firebase-ios-sdk/issues/3818)
  - [#3876](https://github.com/firebase/firebase-ios-sdk/issues/3876)
  - [#5837](https://github.com/firebase/firebase-ios-sdk/issues/5837) 
  - [#6985](https://github.com/firebase/firebase-ios-sdk/issues/6985)