[この記事は Doug Stevenson、デベロッパー アドボケートによる The Firebase Blog の記事 "Organizing your Firebase-enabled Android app builds " を元に翻訳・加筆したものです。詳しくは元記事をご覧ください。]
Doug Stevenson
デベロッパー アドボケート
多くのデベロッパーの皆様に Firebase を試していただいていることをとてもうれしく思っています。試用環境を本番環境に移行した方もいらっしゃるでしょう。その中で、Android プロジェクトのビルドをどう管理すればよいかについて疑問に思った方もいらっしゃるかもしれません。一番よくある質問は、こんなものではないでしょうか。「毎日の開発データとリリースデータを分けるには、どうすればよいでしょうか?」
分析を行う際には、 実際 のアプリの利用データ(開発時の 人為的 な利用ではないもの)のみを反映させたいと誰もが思うでしょう。また、日々の開発でのクラッシュ データと、公開されているリリース版のクラッシュ データが混在していては不便です。何よりも、開発チームが拡大してアプリが複雑になると、お互いの作業が衝突しないように、各チームメンバーの作業環境を個々のサンドボックスに分割したいと考えるはずです。
ここでは、プロジェクトを設定してこういった状況に対応する方法をいくつか考えてみます。Android でアプリをビルドする場合、もっとも好まれる方式は Android Gradle プラグインの設定機能を活用することです。これは、Firebase コンソール のいくつかの設定と合わせて適用されます。
その設定について説明する前に、まずはいくつかの用語を整理しておきましょう。今回使用する用語は、次のとおりです。
Firebase プロジェクト
[Firebase コンソール] のトップレベルで作成するプロジェクトです。作成したプロジェクトは、カード形式で表示されます。
Firebase アプリ
Firebase プロジェクト内に作成するアプリです。Firebase プロジェクトには、いくつでも Android アプリや iOS アプリを含めることができます。プロジェクトに含まれているアプリはホーム画面に表示され、同じ設定を共有します。また、異なる設定も持っています(この点は後ほど詳しく説明します)。
Android Gradle ビルドタイプ
Android Gradle プラグインはビルド時にアプリの設定を行い、その際にビルドタイプが定義されます。ビルドタイプには、デフォルトで「debug」と「release」の 2 種類があります。この設定は buildTypes ブロックで行われており、必要に応じてビルドタイプを追加することもできます。debug タイプは日々のデプロイ用、release タイプはユーザーへの配布用の設定です。
Android Gradle ビルド フレーバー
ビルド時に Android アプリを設定する際に、オプションで「ビルド フレーバー」を割り当てることができます。これはビルドタイプとほぼ同じですが、ビルド フレーバーを使うと必要に応じてさらに細かい設定を行うことができます。たとえば、ほとんどの機能が同じで、アプリケーション ID や有効にする機能のみが異なる「無償」版と「有償」版の両方のアプリをビルドすることができます。
Android Gradle ビルド バリアント
ビルド バリアント は、ビルドタイプとビルド フレーバーの固有の組み合わせです。アプリのビルド設定では、タイプとフレーバーのそれぞれの組み合わせについて、必ずバリアントが 1 つだけ存在します。たとえば、debug と release というタイプを設定しており、「free」と「paid」というフレーバーを設定している場合、Android Gradle プラグインは「debug/free」、「debug/paid」、「release/free」、「release/paid」という組み合わせのバリアントを生成します。コードからビルドした APK は、必ず 1 つだけバリアントを持っています。
Android アプリケーション ID
アプリを一意に識別する文字列の識別子です。Play ストアで公開する際、他のアプリと重複しない一意の値になっている必要があります。通常は、「com.company.project」のように Java パッケージ名形式のフォーマットを使用します。
Firebase 対応のアプリを効果的に設定する際に重要になる考え方があります。それは、個別のデータ コレクションが必要になるアプリのビルド バリアントごとに固有のアプリケーション ID を割り当てることです。 それには、最初にアプリの build.gradle を設定し、次に Firebase コンソールでミラーの設定を行います。しかし、アプリに最適な設定を決めるためには、プロジェクトとアプリの間で Firebase の各機能がどのように動作しているかについてもう少し知っておく必要があります。
Firebase 機能ごとのデータスコープ
Firebase の機能の中には、同じプロジェクト内のすべてのアプリ(Android、iOS、ウェブ)間で データを共有 するものもあります。これらの機能のデータの「スコープ」は、Firebase プロジェクト全体であると言え、次の機能が該当します。
また、Firebase の機能の中には、同じプロジェクト内のすべてのアプリで 独立してデータ を持つものもあります。これらの機能のスコープは、Firebase プロジェクトの個々のアプリであると言え、次の機能が該当します。
Analytics と Crash Reporting のダッシュボードの上部には、アプリのセレクターがあることにお気づきでしょう。ここから、データを参照したい(プロジェクトで作成されている)個々のアプリを選択できます。
アプリ セレクターが表示されている Analytics ダッシュボード
Firebase の機能の中には、ハイブリッドなスコープを持つものもあります。次の機能では、特定の操作の対象とするアプリの数を自由に選択できます。
Remote Config は、プロジェクト内のアプリ間で異なる値を設定することができますが、デフォルトではすべてのアプリに同じ値が設定されます。
Notifications は、コンソールで選択したプロジェクト内の 1 つまたは複数のアプリを対象にできます。
Dynamic Links は、1 つの Android および / または 1 つの iOS アプリが対象になります。
どちらを対象にするかは、現在のプラットフォームに基づいてリンク自身が判断します。
Firebase Test Lab for Android は特殊なケースです。この機能には課金が有効になったプロジェクトが必要ですが、1 つのプロジェクトという制約はなく、任意の APK を対象にすることができます。そのため、無償プランで Firebase の開発を行いつつ有償プランの Test Lab で APK をテストしたい場合は、Test Lab 専用のまったく新しいプロジェクトを作成し、課金を有効にすることをお勧めします。Firebase 統合の有無に関わらず、このプロジェクトでどのようなアプリでもテストできます。
仕組みがわかったところで、現実的ないくつかの実例を見てみましょう。いくつかの設定用レシピも紹介します。この中の 1 つ、あるいはこの中の方法を組み合わせることによって、状況に最適な方式が見つかるでしょう。
小規模チームとシンプルなアプリ
個人デベロッパーや小規模なチームの場合、アプリはかなりシンプルなはずです。そのため、アナリティクスと障害レポートで日々のデバッグと公開リリースビルドを分けるだけで済みます。このケースでは、デバッグとリリースで別のアプリケーション ID を持つことができるようにアプリを設定すれば十分です。次のような簡単な Gradle 設定をするとよいでしょう。
defaultConfig {
applicationId "com.company.project"
// etc...
}
buildTypes {
debug {
applicationIdSuffix ".debug"
}
release {
// etc...
}
}
この例では、リリースビルドに適用されるアプリケーション ID は「com.company.project」ですが、デバッグビルドのアプリケーション ID は「com.company.project.debug」になります。このような接尾語を使わなければならないということではありません。まったく新しい applicationId の値を指定することもできます。
次に、Firebase コンソールで 1 つのプロジェクトを作成し、そのプロジェクト内にそれぞれのビルドタイプに対応する 2 つのアプリを作ります。デバッグアプリではアプリケーション ID「com.company.project.debug」を使用し、リリースアプリでは「com.company.project」を使用します。SHA-1 ハッシュが必要な Firebase 機能を使用している場合は、各ビルドに署名する際に使う別々のキーが SHA-1 ハッシュにも反映されている必要があります。
1 つのプロジェクト内にあり、アプリ ID が異なるデバッグ用とリリース用の 2 つのアプリ
両方 のアプリを作成できたら、コンソールから google-services.json ファイルをダウンロードしてアプリに配置します。このファイルの中を見てみると、両方のアプリが記述されていることがわかるでしょう。Google サービス プラグインは、各バリアントのビルドの際にその設定が使われたかを検出します。
"client_info": {
"mobilesdk_app_id": "...",
"android_client_info": {
"package_name": "com.company.project.debug "
}
},
"client_info": {
"mobilesdk_app_id": "...",
"android_client_info": {
"package_name": "com.company.project "
}
google-services.json は、プロジェクト内のすべての Android アプリを含む
このプロジェクトが課金プランかどうかを知っておくことは重要です。課金は、 両方の アプリの帯域幅とストレージに対して行われます。そのため、開発中に大量のデータを取得すると、課金額が増加する可能性があります。課金額に驚いてしまうことがないように、[課金プラン] をよく理解しておいてください。
また、注意すべき重要な点は、この設定では、開発中も完全リリース版のアプリで実際のユーザーが使うものと同じデータを使用することです。Realtime Database のデータを破壊する予定だったり、開発中に Remote Config の値を実験する場合、この方法はあまり安全とは言えません。
大規模チームと安全な開発
ライブデータを使って開発を行うという先ほどのレシピは問題かもしれません。多くのメンバーを抱える大規模チームで安全でない形でデータを更新する場合や、本番データを破損させるリスクを防ぎたい場合には、複数のプロジェクトをセットアップして開発データを本番データから分離させる必要があります。実は、チーム内のひとりひとりが無償版の個々の「サンドボックス」プロジェクトを使い、他の人や課金に影響を与えずに安全な実験を行うこともできます。
このような環境は、build.gradle に特別な設定をしなくても実現でき、全員が同じアプリケーション ID を使いつつ、サンドボックス プロジェクト内にアプリを作成できます。ただし、これには署名を行うための一意なデバッグキーが必要です。Android SDK ツールは、SDK の各ユーザーに一意なデバッグキーを作成していますので、この点は通常は問題になりません。しかし、Firebase コンソールは、アプリケーション ID と SHA-1 キーのペアが重複したアプリの作成を許可しないことに注意する必要があります。このペアは、 すべて のアカウントの すべて のプロジェクトの すべて のアプリで一意でなければなりません。そのため、チームのメンバーがデバッグキーを共有している場合、この設定は動作しません。
Firebase コンソールはパッケージ名と SHA-1 の組み合わせの重複を許可しない
この仕組みはそれぞれのメンバーの環境を分離する際に便利ですが、一点だけ気をつけるべきことがあります。すべてのデベロッパーがそれぞれのプロジェクトを作ることになるため、いくつかの重複した設定を行わないとプロジェクトが正しく動作しない可能性もあります。たとえば、新しいプロジェクト用のデータベースには、あらかじめいくつかのデータを入れておかなければ利用開始できないかもしれません。また、正しいセキュリティ ルールも重複して設定する必要があります。Remote Configs にも適切な値を設定する必要があるかもしれません。Authentication にも同じような設定が必要になる場合があります。さらに、すべてのデベロッパーが自分のプロジェクト用に生成された google-services.json ファイルを使う必要があります。また、このファイルをソース管理システムにチェックインしては いけません 。これは、チームメンバー間での競合を避けるためです。
開発、QA、ステージング、本番の各環境の分離
複数の環境間でデータを分離する必要がある状況では、上記の大規模チーム向けの設定と同じ方法で設定するとよいでしょう。もちろん、各環境ごとに異なるプロジェクトを作成する必要があります。それぞれの環境は、同じアカウントで管理しても、別のアカウントで管理しても構いません。
ビルド対象の環境を簡単に選択できるように、それぞれの環境向けのアプリに対するビルド フレーバーを活用できます。たとえば、開発、QA、本番の各環境間でデータを分離させる場合、アプリの build.gradle の buildTypes ブロックの隣にある productFlavors ブロックに 3 つのビルド フレーバーを定義します。次の例をご覧ください。
productFlavors {
dev {
}
qa {
}
prod {
}
}
この場合、バリアントは別々に存在しますが、各バリアント間で異なるものはありません。バリアント間で同じアプリケーション ID が共有されますが、これは問題にはなりません。あるいは、ID を分けたい場合には、個別の ID を割り当てることもできます。どちらのケースも、フレーバー固有のディレクトリに各プロジェクトの google-services.json ファイルを入れておく必要があります。上記の各フレーバーが定義されている場合、Android Gradle プラグインはデフォルトで次の規則に基づいてディレクトリを配置します。
app/
src/
main/
dev/
google-services.json (for dev only)
qa/
google-services.json (for qa only)
prod/
google-services.json (for prod only)
各フレーバーのディレクトリは、src ディレクトリ内にある通常プロジェクトのコードが格納されている main ディレクトリと隣り合う場所にあります。各フレーバー名がディレクトリ名となる点に注意してください。このような構造になっているため、各プロジェクト用の google-services.json を直接専用のディレクトリに入れることができます。これによって、アプリの「dev」フレーバーをビルドしたい場合、Android Studio のビルド バリアントを指定するウィンドウから「devDebug」を選択するか、Gradle のコマンドラインでそのバリアントのビルドタスクである「assembleDevDebug」を対象にすることができます。
ご質問がある場合
今回掲載した情報に該当しないアプリのビルドを行うという珍しい状況にある方は、遠慮なく firebase-talk Google Group から質問をお寄せください。緊急のサポートが必要な件については、Firebase Support サイトから問題をお送りください。また、私の Twitter アカウント CodingDoug もぜひフォローしてください。
Posted by Yoshifumi Yamaguchi - Developer Relations Team