Firebase Remote Config を使ってみる


Firebase Remote Config を使用すると、アプリでパラメータを定義し、それらの値をクラウドで更新できます。これにより、アプリのアップデートを配布しなくてもアプリの外観や動作を変更できます。このガイドでは、作業を開始するための手順について説明し、サンプルコードをいくつかご紹介します(すべてのサンプルコードは firebase/quickstart-iOS GitHub リポジトリからダウンロードまたはクローンを作成できます)。

ステップ 1: アプリに Remote Config を追加する

  1. まだ追加していない場合は、Apple プロジェクトに Firebase を追加します。

  2. Remote Config で、ユーザー プロパティとオーディエンスを対象としたアプリ インスタンスの条件付きターゲティングを行うには、Google Analytics が必要です。プロジェクトで Google Analytics を有効にしてください。

  3. 次の例のように、シングルトン Remote Config オブジェクトを作成します。

    Swift

    remoteConfig = RemoteConfig.remoteConfig() let settings = RemoteConfigSettings() settings.minimumFetchInterval = 0 remoteConfig.configSettings = settings

    Objective-C

    self.remoteConfig = [FIRRemoteConfig remoteConfig]; FIRRemoteConfigSettings *remoteConfigSettings = [[FIRRemoteConfigSettings alloc] init]; remoteConfigSettings.minimumFetchInterval = 0; self.remoteConfig.configSettings = remoteConfigSettings;

このオブジェクトは、アプリ内デフォルト パラメータ値の保存、更新されたパラメータ値の Remote Config バックエンドからのフェッチ、フェッチされた値がアプリで使用できるようになるタイミングの制御に使用されます。

開発時には、比較的短い最小フェッチ間隔を設定することをおすすめします。詳細については、スロットル処理をご覧ください。

ステップ 2: アプリ内のデフォルト パラメータ値を設定する

アプリ内デフォルト パラメータ値を Remote Config オブジェクトに設定すると、Remote Config バックエンドに接続する前にアプリを意図したとおりに動作させることができます。また、バックエンド側に値が設定されていない場合は、これらのデフォルト値を使用できます。

  1. NSDictionary オブジェクトまたは plist ファイルを使用して、一連のパラメータ名とデフォルト パラメータ値を定義します。

    Remote Config バックエンド パラメータ値をすでに構成している場合は、すべてのデフォルト値を含む生成された plist ファイルをダウンロードして、Xcode プロジェクトに保存できます。

    REST

     curl --compressed -D headers -H "Authorization: Bearer token -X GET https://firebaseremoteconfig.googleapis.com/v1/projects/my-project-id/remoteConfig:downloadDefaults?format=PLIST -o RemoteConfigDefaults.plist 

    Firebase コンソール

    1. [パラメータ] タブで メニューを開き、[デフォルト値をダウンロード] を選択します。

    2. メッセージが表示されたら、[.plist(iOS 用)] を有効にして、[ファイルをダウンロード] をクリックします。

  2. setDefaults: を使用して、これらの値を Remote Config オブジェクトに追加します。次の例では、plist ファイルからアプリ内デフォルト値を設定します。

    Swift

    remoteConfig.setDefaults(fromPlist: "RemoteConfigDefaults")

    Objective-C

    [self.remoteConfig setDefaultsFromPlistFileName:@"RemoteConfigDefaults"];

ステップ 3: アプリ内で使用するパラメータ値を取得する

ここまでの手順で、パラメータ値を Remote Config オブジェクトから取得できるようになりました。Remote Config バックエンドに値を設定し、フェッチして有効化すると、それらの値をアプリで使用できるようになります。または、setDefaults: を使用して、構成したアプリ内パラメータ値を取得します。アプリ内パラメータ値を取得するには、configValueForKey: メソッドを呼び出します。このとき、引数としてパラメータキーを指定します。

let remoteConfig = RemoteConfig.remoteConfig()  // Retrieve a parameter value using configValueForKey let welcomeMessageValue = remoteConfig.configValue(forKey: "welcome_message") let welcomeMessage = welcomeMessageValue.stringValue  let featureFlagValue = remoteConfig.configValue(forKey: "new_feature_flag") let isFeatureEnabled = featureFlagValue.boolValue 

Swift でこれらの値にアクセスする、読みやすくて便利な方法は、Swift の下付き文字の表記を使用する方法です。

let remoteConfig = RemoteConfig.remoteConfig()  // Retrieve a string parameter value let welcomeMessage = remoteConfig["welcome_message"].stringValue  // Retrieve a boolean parameter value let isFeatureEnabled = remoteConfig["new_feature_flag"].boolValue  // Retrieve a number parameter value let maxItemCount = remoteConfig["max_items"].numberValue.intValue 

Codable を使用して型安全な構成を行う

より複雑な構成の場合は、Swift の Codable プロトコルを使用して、Remote Config から構造化データをデコードできます。これにより、型安全な構成管理が可能になり、複雑なオブジェクトの操作が簡素化されます。

// Define a Codable struct for your configuration struct AppFeatureConfig: Codable {   let isNewFeatureEnabled: Bool   let maxUploadSize: Int   let themeColors: [String: String] }  // Fetch and decode the configuration func configureAppFeatures() {   let remoteConfig = RemoteConfig.remoteConfig()   remoteConfig.fetchAndActivate { status, error in     guard error == nil else { return }      do {       let featureConfig = try remoteConfig["app_feature_config"].decoded(asType: AppFeatureConfig.self)       configureApp(with: featureConfig)     } catch {       // Handle decoding errors       print("Failed to decode configuration: \(error)")     }   } } 

この方法では、次のことが可能です。

  • 複雑な構成構造を定義する。
  • JSON 構成を自動的に解析する。
  • Remote Config 値にアクセスする際の型安全性を確保する。
  • 構造化された Remote Config テンプレートを処理するための、読みやすくクリーンなコードを提供する。

SwiftUI で宣言的な構成にプロパティ ラッパーを使用する

プロパティ ラッパーは、プロパティ宣言にカスタム動作を追加できる強力な Swift 機能です。SwiftUI では、プロパティ ラッパーを使用して、状態、バインディング、その他のプロパティの動作を管理します。詳細については、Swift 言語ガイドをご覧ください。

struct ContentView: View {   @RemoteConfigProperty(key: "cardColor", fallback: "#f05138")   var cardColor    var body: some View {     VStack {       Text("Dynamic Configuration")         .background(Color(hex: cardColor))     }     .onAppear {       RemoteConfig.remoteConfig().fetchAndActivate()     }   } } 

SwiftUI で宣言的に Remote Config 値にアクセスする場合は、@RemoteConfigProperty プロパティ ラッパーを使用します。デフォルト値のサポートが組み込まれており、構成管理が簡素化されます。

ステップ 4: パラメータ値を設定する

Firebase コンソールまたは Remote Config バックエンド API を使用して、バックエンドの新しいデフォルト値を作成できます。このデフォルト値は、目的の条件付きロジックまたはユーザー ターゲティングに従って、アプリ内の値をオーバーライドします。このセクションでは、Firebase コンソールでこれらの値を作成するための手順を説明します。

  1. Firebase コンソールでプロジェクトを開きます。
  2. メニューから [Remote Config] を選択して、Remote Config ダッシュボードを表示します。
  3. アプリで定義したパラメータと同じ名前のパラメータを定義します。それぞれのパラメータにデフォルト値を設定できます(最終的にはアプリ内デフォルト値をオーバーライドします)。また、条件値を設定することもできます。詳細については、Remote Config のパラメータと条件をご覧ください。
  4. カスタム シグナル条件を使用する場合は、属性とその値を定義します。次の例は、カスタム シグナル条件を定義する方法を示しています。

    Swift

      Task {       let customSignals: [String: CustomSignalValue?] = [       "city": .string("Tokyo"),       "preferred_event_category": .string("sports")     ]      do {       try await remoteConfig.setCustomSignals(customSignals)       print("Custom signals set successfully!")       } catch {           print("Error setting custom signals: \(error)")       } }

    Objective-C

      dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{     NSDictionary *customSignals = @{       @"city": @"Tokyo",       @"preferred_event_category": @"sports"     };      [self.remoteConfig setCustomSignals:customSignals withCompletion:^(NSError * _Nullable error) {         if (error) {             NSLog(@"Error setting custom signals: %@", error);         } else {             NSLog(@"Custom signals set successfully!");         }   }]; });

ステップ 5: 値をフェッチして有効にする

Remote Config からパラメータ値をフェッチするには、fetchWithCompletionHandler: メソッドまたは fetchWithExpirationDuration:completionHandler: メソッドを呼び出します。バックエンドに設定したすべての値がフェッチされ、Remote Config オブジェクトにキャッシュ保存されます。

1 回の呼び出しで値をフェッチして有効化する場合は、fetchAndActivateWithCompletionHandler: を使用します。

この例では、キャッシュに保存された値の代わりに Remote Config バックエンドから値をフェッチし、それらの値をアプリで使用できるようにするために activateWithCompletionHandler: を呼び出します。

Swift

remoteConfig.fetch { (status, error) -> Void in   if status == .success {     print("Config fetched!")     self.remoteConfig.activate { changed, error in       // ...     }   } else {     print("Config not fetched")     print("Error: \(error?.localizedDescription ?? "No error available.")")   }   self.displayWelcome() }

Objective-C

[self.remoteConfig fetchWithCompletionHandler:^(FIRRemoteConfigFetchStatus status, NSError *error) {     if (status == FIRRemoteConfigFetchStatusSuccess) {         NSLog(@"Config fetched!");       [self.remoteConfig activateWithCompletion:^(BOOL changed, NSError * _Nullable error) {         if (error != nil) {           NSLog(@"Activate error: %@", error.localizedDescription);         } else {           dispatch_async(dispatch_get_main_queue(), ^{             [self displayWelcome];           });         }       }];     } else {         NSLog(@"Config not fetched");         NSLog(@"Error %@", error.localizedDescription);     } }];

これらの更新されたパラメータ値はアプリの動作と外観に影響するので、スムーズなユーザー エクスペリエンスを実現するタイミング(次にユーザーがアプリを開いたときなど)でフェッチ済みの値を有効化する必要があります。詳細と例については、Remote Config の読み込み方法をご覧ください。

ステップ 6: リアルタイムで更新をリッスンする

パラメータ値をフェッチしたら、リアルタイム Remote Config を使用して、Remote Config バックエンドからの更新をリッスンできます。更新が利用可能になると、リアルタイム Remote Config によって接続済みデバイスに通知され、新しいバージョンの Remote Config を公開すると変更が自動的にフェッチされます。

リアルタイム更新は、Apple プラットフォーム用の Firebase SDK v10.7.0 以降でサポートされています。

  1. アプリで addOnConfigUpdateListener を呼び出して更新のリッスンを開始し、新しいパラメータ値を自動的にフェッチします。次の例では、更新をリッスンし、activateWithCompletionHandler が呼び出されると、新しくフェッチした値を使用して、更新されたウェルカム メッセージを表示します。

    Swift

    remoteConfig.addOnConfigUpdateListener { configUpdate, error in   guard let configUpdate, error == nil else {     print("Error listening for config updates: \(error)")   }    print("Updated keys: \(configUpdate.updatedKeys)")    self.remoteConfig.activate { changed, error in     guard error == nil else { return self.displayError(error) }     DispatchQueue.main.async {       self.displayWelcome()     }   } }

    Objective-C

    __weak __typeof__(self) weakSelf = self; [self.remoteConfig addOnConfigUpdateListener:^(FIRRemoteConfigUpdate * _Nonnull configUpdate, NSError * _Nullable error) {   if (error != nil) {     NSLog(@"Error listening for config updates %@", error.localizedDescription);   } else {     NSLog(@"Updated keys: %@", configUpdate.updatedKeys);      __typeof__(self) strongSelf = weakSelf;     [strongSelf.remoteConfig activateWithCompletion:^(BOOL changed, NSError * _Nullable error) {       if (error != nil) {         NSLog(@"Activate error %@", error.localizedDescription);       }        dispatch_async(dispatch_get_main_queue(), ^{         [strongSelf displayWelcome];       });     }];   } }];
  2. 新しいバージョンの Remote Config を次回公開すると、アプリを実行して変更をリッスンしているデバイスが完了ハンドラを呼び出します。

スロットル処理

アプリが短期間に何度もフェッチすると、フェッチ呼び出しが抑制され、SDK から FIRRemoteConfigFetchStatusThrottled が返されます。バージョン 6.3.0 よりも前の SDK では、フェッチ リクエストは 60 分間に 5 回までと制限されていました(新しいバージョンでは制限が緩和されています)。

アプリの開発では、キャッシュを頻繁に(1 時間に何度も)フェッチして有効にし、アプリの開発とテストを迅速にイテレーションすることをおすすめします。リアルタイム Remote Config の更新は、サーバーで構成ファイルが更新されると、キャッシュを自動的にバイパスします。多数の開発者がいるプロジェクトで迅速なイテレーションに対応するには、アプリ内で最小フェッチ間隔(MinimumFetchInterval)を小さく設定した FIRRemoteConfigSettings プロパティを一時的に追加します。

Remote Config のデフォルトのフェッチ間隔は 12 時間であり、本番環境で推奨されるフェッチ間隔もこの値です。この場合、実際にフェッチ呼び出しが行われた回数に関係なく、12 時間の期間内で構成がバックエンドから複数回フェッチされることはありません。具体的には、次の順で最小フェッチ間隔が決定されます。

  1. fetch(long) のパラメータ
  2. FIRRemoteConfigSettings.MinimumFetchInterval のパラメータ
  3. デフォルト値(12 時間)

次のステップ

Remote Configユースケースに関する詳細な情報が必要な方は、主要なコンセプトと高度な戦略に関する以下のドキュメントをご覧ください。