🔥

Swift Package ManagerでXCFramework形式のFirebaseを使って、ビルド時間を大幅に短縮する

2022/04/28に公開

Firebaseライブラリでは、XCFramework形式のバイナリビルドが提供されています。バイナリビルドを使うと、ライブラリをビルドしないためアプリ全体のビルド時間を削減できます。調査した結果、Swift Package Manager(SPM)でバージョン管理しつつバイナリ版のFirebaseライブラリを利用できたので、その方法を紹介します。

結論

  1. XcodeのAdd Packageshttps://github.com/akaffenberger/firebase-ios-sdk-xcframeworks を追加します[1]。バージョニングはfirebaseと同じものが使えます。
  2. ターゲットのBuild Settingsから、Other Linker Flagsに-ObjCを入れます[2]

なお、FirebaseFirestoreSwiftなど、Beta版の機能はバイナリに含まれていないので利用できません。
→ (2022.05.13追記) 5/3にリリースされたv9.0.0で(サービス名)SwiftパッケージがGAになり、FirebaseInAppMessagingSwiftを除くライブラリのバイナリも利用できるようになりました!これにより、バイナリ版を利用した上でasync/awaitを使いつつfirebaseの各機能を利用できるようになります[3]

前提

Firebase SDK for iOSでは、XCFramework形式でビルド済みライブラリが提供されています。公式リポジトリのreleasesページにて、Firebaseの全サービスのXCFrameworkをダウンロードできます。

このzipファイルを開くと、以下のようになっています。

- Firebase.h: 各サービスimport用ヘッダ定義
- module.modulemap: modulemap定義
- NOTICES: 依存ライブラリのオープンソースライセンス一覧
- Firebase***: サービスごとのXCFramework一式。XCFrameworkごとにInfo.plistとアーキテクチャごとのXCFramworkの実体を持つ。

これらのファイルをプロジェクトに導入することで、Firebaseのサービスで利用できるようになります。

XCFrameworkを使う方法

以下の2種類があります。

  1. firebase-ios-sdk-xcframeworksライブラリを使う方法
  2. (自前でライブラリを依存させる)

2021年12月頃に1.が開発され、SPM上でバージョン管理ができるようになっています。ライブラリ管理のしやすさとビルド時間の削減を両立できておすすめです。

1. firebase-ios-sdk-xcframeworksライブラリを使う方法

akaffenberger氏が提供しているfirebase-ios-sdk-xcframeworksライブラリを利用します。本ライブラリはGitHub Actionで大体2時間ごとにfirebase公式の最新リリースを見に行くようになっており、最新のバイナリのリリースがcommitされる仕組みとなっています。

上記仕組みのため、SPMで上記リポジトリを登録することで、firebaseの最新バイナリを利用できます。すでにSPMでfirebase-ios-sdkを登録している場合は、そちらを削除して上記リポジトリを登録するとOKです。

また、プロジェクトのBuild Settingsから、Other Linker Flagに-ObjCを入れるようにしてください。このフラグがないと、ビルドは通るものの実行時に結果が返ってこないなど、Firebaseライブラリが正常に動作しません。


2. (おまけ) 自前でライブラリを依存させる

どのようにすればFirebaseのXCFrameworkを自前で使えるかどうか、具体例を記載しています。通常の用途では2.の方法は管理が煩雑になるものの、参考として記載しています。

サンプルコード

公式のXCFrameworkについて、bin/pull_firebase_xcframeworks.shによりダウンロード・抽出しています。抽出したXCFrameworkはxcframeworks/firebase下に自動的に同期(rsync)されるため、後はプロジェクト側で下記の設定などを行えばOKです。

https://github.com/Niccari/azure-pipeline-spm-caching/tree/feature/use_binary_firebase

プロジェクトの設定

以下、初回導入時のみ実施

  • USER_HEADER_SEARCH_PATHS = "xcframeworks/firebase/**" を足す (firebase.h, modle.modulemapを認識させるため)
  • Other Linker Flagsに-ObjCフラグを追加

ライブラリにアップデートがある、もしくは利用サービスが変わる度に実施

  • xcframeworks/firebase/をXcodeにドラッグアンドドロップする

XCFramework抽出スクリプト

bin/pull_firebase_xcframeworks.sh
#!/bin/bash

# *** CONFIG ***
VERSION="v8.15.0"
DEPENDENCIES=(
  "FirebaseAnalytics"
  "FirebaseAuth"
  "FirebaseFirestore"
  "FirebaseFunctions"
  "FirebaseStorage"
)
EXCLUDE_ARCHES=(
  "tvos"
  "macos"
  "maccatalyst"
)
REQUIRED_FILES=(
  "Firebase.h"
  "module.modulemap"
)

# *** CODES ***

TARGET_PATH="../xcframeworks/Firebase"

if [ -d $TARGET_PATH ]; then
  rm -r $TARGET_PATH
fi
# fetch xcframeworks
wget https://github.com/firebase/firebase-ios-sdk/releases/download/$VERSION/Firebase.zip -O Firebase.zip
unzip Firebase.zip
rm Firebase.zip

#copy modulemap, header
mkdir $TARGET_PATH
for dep in ${REQUIRED_FILES[@]};
do
  cp Firebase/$dep ${TARGET_PATH}/$dep
done

# find all xcworkspaces in DEPENDENCIES
greps="grep"
for dep in ${DEPENDENCIES[@]};
do
  greps="$greps -e $dep"
done
xcframeworks=$(find Firebase -name "*.xcframework" -maxdepth 2 | $greps)

# find all xcworkspaces in DEPENDENCIES
exclude_arch_args=""
for arch in ${EXCLUDE_ARCHES[@]};
do
  exclude_arch_args="$exclude_arch_args --exclude=*${arch}*"
done

# copy xcworkspaces but not duplicated (their version must be same)
copied_xcframeworks=""
for xcframework_path in ${xcframeworks[@]};
do
  xcframework_name=$(basename $xcframework_path)
  if [[ ! "$copied_xcframeworks" == *"$xcframework_name"* ]]; then
    copied_xcframeworks="$copied_xcframeworks $xcframework_name"
    rsync -a $exclude_arch_args $xcframework_path $TARGET_PATH
  fi
done

# clean up
rm -r Firebase

echo "Firebase dependency injected."

本コードの処理の流れは以下です。

  1. firebase-ios-sdkのXCFrameworkが入ったzipを取得、解凍する
  2. module.modulemap, Firebase.hをプロジェクトに追加する
  3. 必要なFirebase系ライブラリについて、依存するXCFrameworkの一覧を取得
  4. XCFrameworkをプロジェクトのxcframeworks/Firebase下にコピーする。ただし、すでにコピーしたXCFrameworkはコピーしない※
  5. 一時ファイルの削除

※ 同一firebaseバージョンにおいてXCFrameworkは同一なので、どれか1つだけをコピーすればOKです

このコードについて、以下の設定があります。必要に応じ書き換えることで、コピーされるXCFrameworksをアップデートor整理することができます。

  • VERSION: Firebaseのバージョン
  • DEPENDENCIES: Firebaseのうち、どのサービスを使うか
  • EXCLUDE_ARCHES: 除外するXCFrameworkのアーキテクチャ(tvos, macos, iosなど)。部分一致で判定する
脚注
  1. 有志で開発されたライブラリになるので、Firebase公式のサポートが必要な場合は適用が困難となります。 ↩︎

  2. Firebase を Apple プロジェクトに追加する#フレームワーク ↩︎

  3. Firebase Apple SDK Release Notes Version 9.0.0 - May 3, 2022 ↩︎

Discussion