Catch up on everything we announced at this year's Firebase Summit. Learn more

원격 구성 업데이트의 실시간 전파

Firebase용 Cloud Functions에서 제공하는 원격 구성 백그라운드 함수 트리거를 FCM과 함께 사용하면 실시간으로 원격 구성 업데이트를 전파할 수 있습니다. 이 시나리오에서는 대시보드 또는 API의 원격 구성 템플릿을 게시하거나 롤백할 때 트리거되는 함수를 만듭니다. 템플릿을 업데이트하면 FCM 메시지를 보내는 함수가 트리거되고, 이 함수를 통해 클라이언트는 기존 구성이 비활성 상태이고 다음번에 해당 서버에서 구성을 가져와야 한다는 사실을 알 수 있습니다.

Cloud Functions를 통해 FCM 알림을 트리거하는 원격 구성 업데이트를 보여주는 다이어그램

이 문서의 나머지 부분에 나와 있는 단계별 안내에 따라 실시간으로 원격 구성 업데이트를 전파할 수 있습니다.

클라이언트 앱 인스턴스의 FCM 주제 구독

전체 사용자층과 같은 대규모 그룹의 클라이언트 앱 인스턴스를 대상으로 FCM 메시지를 보내는 데에는 주제 메시징이 가장 효율적인 메커니즘입니다. 실시간 원격 구성 업데이트를 수신하려면 각 앱 인스턴스가 주제 이름(예: PUSH_RC)을 구독해야 합니다.

Swift

extension AppDelegate : MessagingDelegate {
    func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) {
        messaging.subscribe(toTopic: "PUSH_RC") { error in
            print("Subscribed to PUSH_RC topic")
        }
    }
}
    

Objective-C

- (void)messaging:(FIRMessaging *)messaging didReceiveRegistrationToken:(NSString *)fcmToken {
    [[FIRMessaging messaging] subscribeToTopic:@"PUSH_RC" completion:^(NSError * _Nullable error) {
        NSLog(@"Subscribed to PUSH_RC topic");
    }];
}
    

Android

@Override
public void onNewToken(String s) {
    FirebaseMessaging.getInstance().subscribeToTopic("PUSH_RC");
}
    

템플릿 업데이트 시 FCM 핑을 보내는 함수 만들기

새로운 구성 버전 게시 또는 이전 버전으로 롤백을 포함한 원격 구성 이벤트에 대한 응답으로 함수를 트리거할 수 있습니다. 실시간으로 템플릿 업데이트를 전파하려면 템플릿 게시 이벤트를 수신 대기하는 함수를 만든 다음 함수의 FCM Admin SDK를 사용하여 클라이언트 앱 인스턴스로 자동 핑을 보내세요.

exports.pushConfig = functions.remoteConfig.onUpdate(versionMetadata => {
  // Create FCM payload to send data message to PUSH_RC topic.
  const payload = {
    topic: "PUSH_RC",
    data: {
      "CONFIG_STATE": "STALE"
    }
  };
  // Use the Admin SDK to send the ping via FCM.
  return admin.messaging().send(payload).then(resp => {
    console.log(resp);
    return null;
  });
});

이 함수는 CONFIG_STATE 매개변수를 설정한 후 PUSH_RC 주제를 구독한 모든 클라이언트에게 FCM 메시지의 데이터 페이로드로 보냅니다.

클라이언트의 원격 구성 상태 설정

앞 단계에서 나온 데이터 페이로드는 앱의 공유 환경설정에서 CONFIG_STATE를 항상 STALE로 설정합니다. 이는 앞서 앱에 저장되었던 원격 구성 템플릿이 새로 업데이트된 템플릿의 생성으로 인해 비활성 상태가 되었으며 새로운 템플릿의 게시가 함수를 트리거했음을 나타냅니다. 이 조건을 테스트하려면 알림 핸들러를 업데이트하세요.

Swift

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any],
                 fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {

    if (userInfo.index(forKey: "CONFIG_STATE") != nil) {
        print("Config set to stale")
        UserDefaults.standard.set(true, forKey:"CONFIG_STALE")
    }

    completionHandler(UIBackgroundFetchResult.newData)
}
    

Objective-C

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {

    if (userInfo[@"CONFIG_STATE"]) {
        NSLog(@"Config set to stale");
        [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"CONFIG_STALE"];
    }

    completionHandler(UIBackgroundFetchResultNewData);
}
    

Android

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
    if (remoteMessage.getData().containsKey("CONFIG_STATE")) {
        SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
        sharedPreferences.edit().putBoolean("CONFIG_STALE", true).apply();
    }
}
    

앱 시작 시 원격 구성 업데이트 가져오기

Swift

func fetchConfig() {
  welcomeLabel.text = remoteConfig[loadingPhraseConfigKey].stringValue

  var expirationDuration = 3600
  // If your app is using developer mode, expirationDuration is set to 0, so each fetch will
  // retrieve values from the service.
  if remoteConfig.configSettings.isDeveloperModeEnabled || UserDefaults.standard.bool(forKey: "CONFIG_STALE") {
    expirationDuration = 0
  }

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

Objective-C

- (void)fetchConfig {
    self.welcomeLabel.text = self.remoteConfig[kLoadingPhraseConfigKey].stringValue;

    long expirationDuration = 3600;
    // If your app is using developer mode, expirationDuration is set to 0, so each fetch will
    // retrieve values from the Remote Config service.
    if (self.remoteConfig.configSettings.isDeveloperModeEnabled || [[NSUserDefaults standardUserDefaults] boolForKey:@"CONFIG_STALE"]) {
        expirationDuration = 0;
    }

    [self.remoteConfig fetchWithExpirationDuration:expirationDuration completionHandler:^(FIRRemoteConfigFetchStatus status, NSError *error) {
        if (status == FIRRemoteConfigFetchStatusSuccess) {
            NSLog(@"Config fetched!");
            [self.remoteConfig activateFetched];
            [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"CONFIG_STALE"];
        } else {
            NSLog(@"Config not fetched");
            NSLog(@"Error %@", error.localizedDescription);
        }
        [self displayWelcome];
    }];
}
    

Android

private void fetchWelcomeMessage() {
    mWelcomeTextView.setText(mFirebaseRemoteConfig.getString("loading_phrase"));

    long cacheExpiration = 43200; // 12 hours in seconds.
    // If your app is using developer mode or cache is stale, cacheExpiration is set to 0,
    // so each fetch will retrieve values from the service.
    if (mFirebaseRemoteConfig.getInfo().getConfigSettings().isDeveloperModeEnabled() ||
            mSharedPreferences.getBoolean("CONFIG_STALE", false)) {
        cacheExpiration = 0;
    }

    mFirebaseRemoteConfig.fetch(cacheExpiration)
            .addOnCompleteListener(this, new OnCompleteListener<Void>() {
                @Override
                public void onComplete(@NonNull Task<Void> task) {
                    if (task.isSuccessful()) {
                        Toast.makeText(MainActivity.this, "Fetch Succeeded",
                                Toast.LENGTH_SHORT).show();

                        // After config data is successfully fetched, it must be activated before newly fetched
                        // values are returned.
                        mFirebaseRemoteConfig.activateFetched();
                    } else {
                        Toast.makeText(MainActivity.this, "Fetch Failed",
                                Toast.LENGTH_SHORT).show();
                    }
                    mWelcomeTextView.setText(mFirebaseRemoteConfig.getString("welcome_message"));
                }
            });
}
    

마지막으로 CONFIG_STATESTALE이므로 로컬 스토리지를 무시하고 네트워크에서 원격 구성 가져오기를 강제 적용하는 로직을 앱에 추가하세요. 앱의 네트워크에서 가져오기 빈도가 너무 잦은 경우에는 Firebase에서 제한이 발생할 수 있습니다. 제한을 참조하세요.