複数のプロジェクトを構成する

このページでは、アプリで複数の Firebase プロジェクトを使用する方法について説明します。

多くのアプリは、単一の Firebase プロジェクトと、スタートガイドに記載されているデフォルトの設定のみを必要としています。複数の Firebase プロジェクトを使用すると便利なのは次のような場合です。

  • ビルドタイプやターゲットに基づいて異なる Firebase プロジェクトを使用するように開発環境をセットアップする。
  • アプリで複数の Firebase プロジェクトからコンテンツにアクセスする。

異なる環境に対応する

一般的な利用方法の一つとして、開発環境と本番環境それぞれで個別の Firebase プロジェクトに対応する場合が考えられます。

ウェブ SDK と Admin SDK を構成するには、その初期化関数に値を直接渡します。こうした SDK では、ランタイム チェックを使用して、開発用または本番用の構成変数を選択できます。

Android と Apple プラットフォーム(および、その Unity ラッパーと C++ ラッパー)は、通常、構成ファイル(Apple プラットフォームの場合は GoogleService-Info.plist、Android の場合は google-services.json)から構成を読み込みます。このようなファイルは、Firebase アプリケーション オブジェクト(FIRApp または FirebaseApp)によって参照されるオプション オブジェクト(FIROption または FirebaseOptions)に読み込まれます。

通常、こうしたプラットフォームでの環境の切り換えは、環境ごとにさまざまな構成ファイルを使用して、ビルド時の決定事項として実装されます。

Apple アプリケーションで複数の環境に対応する

デフォルトでは、FirebaseApp.configure() は、アプリケーションにバンドルされている GoogleService-Info.plist ファイルを読み込みます。開発環境と本番環境が Xcode で別々のターゲットとして構成されている場合は、以下の操作が可能です。

  • 両方の GoogleService-Info.plist ファイルをダウンロードする
  • 2 つのファイルを別々のディレクトリに保存する
  • 両方を Xcode プロジェクトに追加する
  • ターゲット メンバーパネルを使用して、さまざまなファイルをさまざまなターゲットに関連付ける

ターゲット メンバーパネル

ビルドが単一のターゲットの一部である場合、最適なオプションは、両方の構成ファイルに一意の名前を付けることです(例: GoogleService-Info-Free.plistGoogleService-Info-Paid.plist)。そして、ランタイム時にどちらの plist を読み込むかを選択します。これを次の例に示します。

// Load a named file.
let filePath = Bundle.main.path(forResource: "MyGoogleService", ofType: "plist")
guard let fileopts = FirebaseOptions(contentsOfFile: filePath!)
  else { assert(false, "Couldn't load config file") }
FirebaseApp.configure(options: fileopts)

Android アプリで複数の環境をサポートする

Android では、google-services.json ファイルは Google サービス Gradle プラグインによって処理され、Android 文字列リソースとなります。作成されるリソースについては、Google サービス プラグインに関するドキュメントの JSON ファイルを処理するをご覧ください。

さまざまなビルド バリアントに対して複数の google-services.json ファイルを設定するには、アプリ モジュールのルートの下に各バリアントの名前を付けた専用ディレクトリを作成して、そこに google-services.json ファイルを配置します。たとえば、「development」および「release」ビルド フレーバーがある場合、構成を次のように編成できます。

app/
    google-services.json
    src/development/google-services.json
    src/release/google-services.json
    ...

詳細については、Google サービス プラグインに関するドキュメントの JSON ファイルを追加するをご覧ください。

その後、これらのリソースは FirebaseInitProvider によって読み込まれます。このプロバイダはアプリケーション コードの前に実行され、それらの値を使用して Firebase API を初期化します。

このプロバイダは、既知の名前を持つリソースを読み取っているだけなので、Google サービス Gradle プラグインを使用するのではなく、文字列リソースをアプリに直接追加することもできます。方法は以下のとおりです。

  • google-services プラグインをルート build.gradle から削除する
  • プロジェクトから google-services.json を削除する
  • 文字列リソースを直接追加する
  • アプリ build.gradle から apply plugin: 'com.google.gms.google-services' を削除する

アプリケーションで複数のプロジェクトを使用する

時に、同じ API を使ってさまざまなプロジェクトにアクセスしなければならないことがあります。たとえば、複数のデータベース インスタンスにアクセスする場合などです。ほとんどの場合、Firebase アプリケーション オブジェクトが中央に配置されており、このオブジェクトが、すべての Firebase API の構成を一元管理しています。このオブジェクトは、標準設定の一環として初期化されます。しかし、1 つのアプリケーションから複数のプロジェクトにアクセスしたい場合は、各 Firebase アプリケーション オブジェクトが個別に各プロジェクトを参照する必要があります。こうした他のインスタンスを初期化するかどうかは、デベロッパー次第です。

いずれの場合も、Firebase アプリケーションの構成データを保持するために、最初に Firebase オプション オブジェクトを作成する必要があります。オプションの詳細については、API リファレンスに関するドキュメントで次のクラスをご覧ください。

これらのクラスを使用してアプリケーションで複数のプロジェクトに対応する例を以下に示します。

Swift

// Configure with manual options. Note that projectID and apiKey, though not
// required by the initializer, are mandatory.
let secondaryOptions = FirebaseOptions(googleAppID: "1:27992087142:ios:2a4732a34787067a",
                                       gcmSenderID: "27992087142")
secondaryOptions.apiKey = "AIzaSyBicqfAZPvMgC7NZkjayUEsrepxuXzZDsk"
secondaryOptions.projectID = "projectid-12345"

// The other options are not mandatory, but may be required
// for specific Firebase products.
secondaryOptions.bundleID = "com.google.firebase.devrel.FiroptionConfiguration"
secondaryOptions.trackingID = "UA-12345678-1"
secondaryOptions.clientID = "27992087142-ola6qe637ulk8780vl8mo5vogegkm23n.apps.googleusercontent.com"
secondaryOptions.databaseURL = "https://myproject.firebaseio.com"
secondaryOptions.storageBucket = "myproject.appspot.com"
secondaryOptions.androidClientID = "12345.apps.googleusercontent.com"
secondaryOptions.deepLinkURLScheme = "myapp://"
secondaryOptions.storageBucket = "projectid-12345.appspot.com"
secondaryOptions.appGroupID = nil

Kotlin+KTX

// Manually configure Firebase Options. The following fields are REQUIRED:
//   - Project ID
//   - App ID
//   - API Key
val options = FirebaseOptions.Builder()
    .setProjectId("my-firebase-project")
    .setApplicationId("1:27992087142:android:ce3b6448250083d1")
    .setApiKey("AIzaSyADUe90ULnQDuGShD9W23RDP0xmeDc6Mvw")
    // .setDatabaseUrl(...)
    // .setStorageBucket(...)
    .build()

Java

// Manually configure Firebase Options. The following fields are REQUIRED:
//   - Project ID
//   - App ID
//   - API Key
FirebaseOptions options = new FirebaseOptions.Builder()
        .setProjectId("my-firebase-project")
        .setApplicationId("1:27992087142:android:ce3b6448250083d1")
        .setApiKey("AIzaSyADUe90ULnQDuGShD9W23RDP0xmeDc6Mvw")
        // setDatabaseURL(...)
        // setStorageBucket(...)
        .build();

ウェブ

// The following fields are REQUIRED:
//  - Project ID
//  - App ID
//  - API Key
const secondaryAppConfig = {
    projectId: "<PROJECT_ID>",
    appId: "<APP_ID>",
    apiKey: "<API_KEY>",
    // databaseURL: "...",
    // storageBucket: "...",
};

C++

firebase::AppOptions secondary_app_options;

// API key, app ID, and project ID are always required.
secondary_app_options.set_api_key("<API_KEY>");
secondary_app_options.set_app_id("<GOOGLE_APP_ID>");
secondary_app_options.set_project_id("<PROJECT_ID>");

// The following options are specific to individual Firebase products
// and may not always be required.
secondary_app_options.set_database_url("<DATABASE_URL>");
secondary_app_options.set_messaging_sender_id("<SENDER_ID>");
secondary_app_options.set_storage_bucket("<STORAGE_BUCKET>");

Unity

Firebase.AppOptions secondaryAppOptions = new Firebase.AppOptions {
  ApiKey = "<API_KEY>",
  AppId = "<GOOGLE_APP_ID>",
  ProjectId = "<PROJECT_ID>"
};

Node.js

const secondaryServiceAccount = require('./path/to/serviceAccountKey.json');

// All required options are specified by the service account,
// add service-specific configuration like databaseURL as needed.
const secondaryAppConfig = {
    credential: cert(secondaryServiceAccount),
    // databaseURL: 'https://<DATABASE_NAME>.firebaseio.com'
};

Java

FileInputStream serviceAccount = new FileInputStream("path/to/serviceAccountKey.json");

FirebaseOptions secondaryAppConfig = new FirebaseOptions.Builder()
  .setCredential(FirebaseCredentials.fromCertificate(serviceAccount))
  .setDatabaseUrl("https://<DATABASE_NAME>.firebaseio.com/")
  .build();

オプション オブジェクトを初期化したら、そのオブジェクトを使用して、追加の Firebase アプリケーション インスタンスを構成できます。以下のすべての例では、secondary という文字列を使用しています。この名前は、アプリケーション インスタンスを取得したり、そのインスタンスを他のインスタンス([DEFAULT] という名前のデフォルト インスタンスなど)と区別したりするために使用されています。他の Firebase プロジェクトの場合は、その使用目的に適した文字列を選択してください。

次のスニペットは、代替 Realtime Database への接続を示しています(他の Firebase 機能の API も同じパターンに従います)。

Swift

// Configure an alternative FIRApp.
FirebaseApp.configure(name: "secondary", options: secondaryOptions)

// Retrieve a previous created named app.
guard let secondary = FirebaseApp.app(name: "secondary")
  else { assert(false, "Could not retrieve secondary app") }


// Retrieve a Real Time Database client configured against a specific app.
let secondaryDb = Database.database(app: secondary)

Kotlin+KTX

// Initialize secondary FirebaseApp.
Firebase.initialize(context = this, options, "secondary")

// Retrieve secondary FirebaseApp.
val secondary = Firebase.app("secondary")
// Get the database for the other app.
val secondaryDatabase = Firebase.database(secondary)

Java

// Initialize with secondary app
FirebaseApp.initializeApp(this /* Context */, options, "secondary");

// Retrieve secondary FirebaseApp
FirebaseApp secondary = FirebaseApp.getInstance("secondary");

ウェブ

// Initialize another app with a different config
const secondaryApp = firebase.initializeApp(secondaryAppConfig, "secondary");
// Access services, such as the Realtime Database
// secondaryApp.database();

C++

firebase::App* secondary_app = firebase::App::Create(secondary_app_options, "Secondary");
firebase::database::Database* secondary_database = firebase::database::Database::GetInstance(secondary_app);

Unity

var secondaryApp = Firebase.FirebaseApp.Create(secondaryAppOptions, "Secondary"));
var secondaryDatabase = Firebase.Database.FirebaseDatabase.getInstance(secondaryApp);

Node.js

// Initialize another app with a different config
const secondary = initializeApp(secondaryAppConfig, 'secondary');
// Access services, such as the Realtime Database
// const secondaryDatabase = secondary.database();

Java

// Initialize another app with a different config
FirebaseApp secondaryApp = FirebaseApp.initializeApp(secondaryAppConfig, "secondary");

// Retrieve the database.
FirebaseDatabase secondaryDatabase = FirebaseDatabase.getInstance(secondaryApp);

アナリティクスのレポートの信頼性を確保する

Google アナリティクスでは、アプリ起動フローの非常に早い段階でイベントが収集されます。場合によっては、これはメインの Firebase アプリ インスタンスが構成される前になります。このような場合、Firebase は Android リソースまたは Apple プラットフォームの GoogleService-Info.plist を参照して、イベントを保存するための正しい Google アプリ ID を検索します。このため、可能な限りデフォルトの構成方法を使用することをおすすめします。

ランタイム構成が必要な場合は、次の点に注意してください。

  1. AdMob を使用していて、推奨に従って起動時に広告をリクエストする場合、リソースベースの構成アプローチを使用しないと、モバイル広告に関連する一部のアナリティクス データを見逃す可能性があります。
  2. アプリの各配布バリアントにつき、指定する Google アプリ ID は 1 つのみとします。たとえば、アプリのバージョン 1 リリース時の構成で特定の GOOGLE_APP_ID を使用し、次にバージョン 2 のアップロード時に異なる ID を使用した場合、アナリティクス データが削除されることがあります。
  3. Apple プラットフォームで実行時に別の構成を提供する場合は、GoogleService-Info.plist をプロジェクトに追加しないでください。見かけ上の GOOGLE_APP_ID が変更され、アナリティクスが失われる可能性があります。