Skip to content

Commit 4e5b83f

Browse files
qdpham13andrewheardkarenyzdanasilver
authored
Merge Realtime into Remote Config (#10060)
* Realtime rc dev (#9807) * Remove commits from non-CLA account. Move TypeDef to private RCNRealtimeConfig file. * Remove completion handler typedef * Format file * Update listener registration description * Realtime rc dev (#9835) * Remove commits from non-CLA account. Move TypeDef to private RCNRealtimeConfig file. * Remove completion handler typedef * Format file * Update listener registration description * Add http streaming and auto fetch. Also add template version number to cache for autofetch. * Format file. * Add unit tests * Format files * fix test * update test and header file * Change templateVersionNumber to ivar * Fix async tests and update NSDictionary changes * Format file * Update fetch time * remove define header * Wrap auto fetch in async queue * Add auto fetch test * Change template version extraction check. * Change realtime error code to start at 8001 * Realtime rc dev (#9914) * Remove commits from non-CLA account. Move TypeDef to private RCNRealtimeConfig file. * Remove completion handler typedef * Format file * Update listener registration description * Add http streaming and auto fetch. Also add template version number to cache for autofetch. * Format file. * Add unit tests * Format files * fix test * update test and header file * Change templateVersionNumber to ivar * Fix async tests and update NSDictionary changes * Format file * Update fetch time * remove define header * Add http stream retry and background change listener. * Wrap auto fetch in async queue * Expose realtime method in public * Update comments * Add auto fetch test * Change template version extraction check. * Change realtime error code to start at 8001 * Change from NSTimer to dispatch. Add flag to guard against retrying. * Format and add comments. * Update tests * Qdpham13 patch 1 (#9913) * Delete .SecondApp-GoogleService-Info.plist * Delete SecondApp-GoogleService-Info.plist * Delete GoogleService-Info.plist * Delete SecondApp-GoogleService-Info.plist * Update ViewController.m * Delete clang-format directory * format * Change to NSExtensionHostWillEnterForegroundNotification * Change to UIApplicationWillEnterForegroundNotification * add import * Remove import, use string literal instead of UIKit enum * add test for new public method * Update template version number retrieval function and update delay * Fix test * Fix test * Update retry seconds and fetch interval seconds * Update ddos to DDoS * Update variable according to style guide. * Replace NSLog with kFIRLoggerRemoteConfig (#10062) * Replace NSLog with kFIRLoggerRemoteConfig * Remove logs and change others from info to debug. * update log messages. * Format files * Realtime rc failsafe (#10067) * Add failsafe logic to request, response and application logic. * Update flag name and conditions. * Format file * Add check for template version number * Format files * Changes based on PR comments * move response parsing logic to separate function and add test for failsafe flag * Update based on PR comments and add method to propagate error to listeners in queue. * Realtime rc merge patch v1 (#10089) * Fix foreground reconnection naming, add background check and flag, add check to see if fetch is currently in progress. * Add check so fetches come only when the template version is greater than the current one. * Format file changes * Add debug log * Make changes based on PR comments. * Resolve failsafe changes * Updating instance var names * change template version check for auto fetch from >= to > * Cherry-pick #10123 into Firebase 9.5.0 * [RC] Fix retry logic to respect max retry count (#10143) * Fix retry logic to respect max retry count * Rename to isRequestInProgress * Save template version in settings (#10162) * Save template version in settings * Format files * set last template version to 0 * Store template version in userDefaults instead of deviceContents * return nil for unsuccessful fetches * fix typo * Realtime rc no change (#10188) * Save template version in settings * Format files * set last template version to 0 * Store template version in userDefaults instead of deviceContents * return nil for unsuccessful fetches * fix typo * put addEtagToHeader flag to fetch and propagate it to surrounding functions * Add excludeEtagHeaderForRealtime flag to RCNConfigFetch * Update mocks for Swift test * Fix flag * Add commentting * reconcile master branch merge conflicts * Revert "Realtime rc no change (#10188)" (#10346) This reverts commit abe7939. In part of implementing a different solution. * Add Http status check to Realtime stream (#10406) * Check status code before retrying * Change time out to 5 and a half minutes * Throw exception if unable to establish connection due to non-retryable status code * Format file * Replace old realtime exceptions with new exceptions (#10482) * Replace old realtime exceptions with new exceptions * Fix word type * Realtime RC Fetch ID (#10499) * Add Realtime specific fetch method and fetch type header changes * Add test * Add comments and format * Fix tests * Update fetch header name * Update tests and edit realtime fetch name and params * refactor remainingAttempts var * Realtime rc backoff (#10483) * Change Realtime back off to use same system as Fetch and persist backoff state * format and fix merge conflict * Save retry count along with other throttling metadata * Update var name * Fix naming * Return ConfigUpdate to realtime listeners (#10578) * diff fetched and active config on realtime fetch * Some refactoring and added tests * Revert some unrelated changes to fetch * Fix formatting * Update branch and fix swift tests * Rename updatedParams to updatedKeys (#10683) * Update Realtime RC service URL. (#10713) * Compare p13n metadata values as dictionaries. (#10756) * Realtime RC 1P Bug Fix: Add checks for retryHttpConnection method (#10770) * Add checks to retry method * Move background check to beginning of retry * Capitalize FetchType header (#10774) * Remove Fetch Duplicate error and fix API misuse error (#10814) * Remove fetch duplicate error * Move completionHandler to bottom of didReceiveData * Remove unused var * Return Server produced error if Http status code is 403 (#10844) * Add API message to enable Realtime * Update error message parsing to return error message from backend * Format file * Add comment and remove unnecessary string * Format and update error checks * Change matcher string * Update matcher string * Address PR comments (#10845) * Address PR comments * Add Realtime Swift mocks * Remove unnecessary mocks * Format files * Format tests * Add Realtime mock * Add missing quote * Fix bugs * Remove import * Update import * Change import * Don't make connection call for Realtime mock * Move around import of RCNConfigSettings * Fix andDo * Update test * Add mockedRealtime flags * trigger integration test * Add integration and unit test * change constant value * Add new RC key * Update update * Remove deleted item * Add registration removal * Fix and format files * remove semicolon * Update error check * remove space * Update capitalization * Add space * Remove spaces * remove more spaces * Remove comment and add swift name * format * Add tests and sampleApp changes for updatedKeys (#10879) * Update tests and sample app * change key name * remove unused var * Add comment * update sampleApp comments * Update comments for public methods * Update backoff commenting * Add changelog entry for real-time updates. (#10942) * Add changelog entry for RC real time updates. * Hyphenation. * Change doc references to hyphenate real-time (#10948) * Change doc references to hyphenate real-time * Run formatter. * Re-word real-time paragraph to flow better. --------- Co-authored-by: Andrew Heard <[email protected]> Co-authored-by: karenyz <[email protected]> Co-authored-by: Karen Zeng <[email protected]> Co-authored-by: Dana Silver <[email protected]> Co-authored-by: Dana Silver <[email protected]>
1 parent 56c48a1 commit 4e5b83f

27 files changed

+1973
-67
lines changed

FirebaseRemoteConfig/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# 10.7.0
2+
- [feature] Added support for real-time config updates. To learn more, see [Get started with Firebase Remote Config](https://firebase.google.com/docs/remote-config/get-started?platform=ios).
3+
14
# 9.3.0
25
- [changed] Arrays and Dictionaries are now supported when initializing defaults from a
36
plist. (#8306)

FirebaseRemoteConfig/Sources/FIRRemoteConfig.m

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,16 @@
2626
#import "FirebaseRemoteConfig/Sources/RCNConfigContent.h"
2727
#import "FirebaseRemoteConfig/Sources/RCNConfigDBManager.h"
2828
#import "FirebaseRemoteConfig/Sources/RCNConfigExperiment.h"
29+
#import "FirebaseRemoteConfig/Sources/RCNConfigRealtime.h"
2930
#import "FirebaseRemoteConfig/Sources/RCNConfigValue_Internal.h"
3031
#import "FirebaseRemoteConfig/Sources/RCNDevice.h"
3132
#import "FirebaseRemoteConfig/Sources/RCNPersonalization.h"
3233

3334
/// Remote Config Error Domain.
3435
/// TODO: Rename according to obj-c style for constants.
3536
NSString *const FIRRemoteConfigErrorDomain = @"com.google.remoteconfig.ErrorDomain";
37+
// Remote Config Realtime Error Domain
38+
NSString *const FIRRemoteConfigUpdateErrorDomain = @"com.google.remoteconfig.update.ErrorDomain";
3639
/// Remote Config Error Info End Time Seconds;
3740
NSString *const FIRRemoteConfigThrottledEndTimeInSecondsKey = @"error_throttled_end_time_seconds";
3841
/// Minimum required time interval between fetch requests made to the backend.
@@ -66,6 +69,7 @@ @implementation FIRRemoteConfig {
6669
RCNConfigSettings *_settings;
6770
RCNConfigFetch *_configFetch;
6871
RCNConfigExperiment *_configExperiment;
72+
RCNConfigRealtime *_configRealtime;
6973
dispatch_queue_t _queue;
7074
NSString *_appName;
7175
NSMutableArray *_listeners;
@@ -165,6 +169,11 @@ - (instancetype)initWithAppName:(NSString *)appName
165169
namespace:_FIRNamespace
166170
options:options];
167171

172+
_configRealtime = [[RCNConfigRealtime alloc] init:_configFetch
173+
settings:_settings
174+
namespace:_FIRNamespace
175+
options:options];
176+
168177
[_settings loadConfigFromMetadataTable];
169178

170179
if (analytics) {
@@ -597,4 +606,11 @@ - (void)setConfigSettings:(FIRRemoteConfigSettings *)configSettings {
597606
dispatch_async(_queue, setConfigSettingsBlock);
598607
}
599608

609+
#pragma mark - Realtime
610+
611+
- (FIRConfigUpdateListenerRegistration *)addOnConfigUpdateListener:
612+
(void (^_Nonnull)(FIRRemoteConfigUpdate *update, NSError *_Nullable error))listener {
613+
return [self->_configRealtime addConfigUpdateListener:listener];
614+
}
615+
600616
@end
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright 2022 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#import <Foundation/Foundation.h>
18+
19+
#import "FirebaseRemoteConfig/Sources/Public/FirebaseRemoteConfig/FIRRemoteConfig.h"
20+
21+
@implementation FIRRemoteConfigUpdate {
22+
NSSet<NSString *> *_updatedKeys;
23+
}
24+
25+
- (instancetype)initWithUpdatedKeys:(NSSet<NSString *> *)updatedKeys {
26+
self = [super init];
27+
if (self) {
28+
_updatedKeys = [updatedKeys copy];
29+
}
30+
return self;
31+
}
32+
33+
@end

FirebaseRemoteConfig/Sources/Private/FIRRemoteConfig_Private.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,19 @@
2121
@class RCNConfigContent;
2222
@class RCNConfigDBManager;
2323
@class RCNConfigFetch;
24+
@class RCNConfigRealtime;
2425
@protocol FIRAnalyticsInterop;
2526

2627
NS_ASSUME_NONNULL_BEGIN
2728

2829
@class RCNConfigSettings;
2930

31+
@interface FIRRemoteConfigUpdate ()
32+
33+
/// Designated initializer.
34+
- (instancetype)initWithUpdatedKeys:(NSSet<NSString *> *)updatedKeys;
35+
@end
36+
3037
@interface FIRRemoteConfig () {
3138
NSString *_FIRNamespace;
3239
}
@@ -37,6 +44,8 @@ NS_ASSUME_NONNULL_BEGIN
3744
/// Config settings are custom settings.
3845
@property(nonatomic, readwrite, strong, nonnull) RCNConfigFetch *configFetch;
3946

47+
@property(nonatomic, readwrite, strong, nonnull) RCNConfigRealtime *configRealtime;
48+
4049
/// Returns the FIRRemoteConfig instance for your namespace and for the default Firebase App.
4150
/// This singleton object contains the complete set of Remote Config parameter values available to
4251
/// the app, including the Active Config and Default Config.. This object also caches values fetched

FirebaseRemoteConfig/Sources/Private/RCNConfigFetch.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ NS_ASSUME_NONNULL_BEGIN
3030
/// Completion handler invoked by NSSessionFetcher.
3131
typedef void (^RCNConfigFetcherCompletion)(NSData *data, NSURLResponse *response, NSError *error);
3232

33+
/// Completion handler invoked after a fetch that contains the updated keys
34+
typedef void (^RCNConfigFetchCompletion)(FIRRemoteConfigFetchStatus status,
35+
FIRRemoteConfigUpdate *update,
36+
NSError *error);
37+
3338
@interface RCNConfigFetch : NSObject
3439

3540
- (instancetype)init NS_UNAVAILABLE;
@@ -50,12 +55,22 @@ typedef void (^RCNConfigFetcherCompletion)(NSData *data, NSURLResponse *response
5055
- (void)fetchConfigWithExpirationDuration:(NSTimeInterval)expirationDuration
5156
completionHandler:(FIRRemoteConfigFetchCompletion)completionHandler;
5257

58+
/// Fetches config data immediately, keyed by namespace. Completion block will be called on the main
59+
/// queue.
60+
/// @param fetchAttemptNumber The number of the fetch attempt.
61+
/// @param completionHandler Callback handler.
62+
- (void)realtimeFetchConfigWithNoExpirationDuration:(NSInteger)fetchAttemptNumber
63+
completionHandler:(RCNConfigFetchCompletion)completionHandler;
64+
5365
/// Add the ability to update NSURLSession's timeout after a session has already been created.
5466
- (void)recreateNetworkSession;
5567

5668
/// Provide fetchSession for tests to override.
5769
@property(nonatomic, readwrite, strong, nonnull) NSURLSession *fetchSession;
5870

71+
/// Provide config template version number for Realtime config client.
72+
@property(nonatomic, copy, nonnull) NSString *templateVersionNumber;
73+
5974
NS_ASSUME_NONNULL_END
6075

6176
@end

FirebaseRemoteConfig/Sources/Private/RCNConfigSettings.h

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@
7979
@property(nonatomic, readwrite, assign) NSString *lastETag;
8080
/// The timestamp of the last eTag update.
8181
@property(nonatomic, readwrite, assign) NSTimeInterval lastETagUpdateTime;
82+
// Last fetched template version.
83+
@property(nonatomic, readwrite, assign) NSString *lastTemplateVersion;
8284

8385
#pragma mark Throttling properties
8486

@@ -90,6 +92,14 @@
9092
@property(nonatomic, readwrite, assign) double exponentialBackoffRetryInterval;
9193
/// Returns the time in seconds until the next request is allowed while in exponential backoff mode.
9294
@property(nonatomic, readonly, assign) NSTimeInterval exponentialBackoffThrottleEndTime;
95+
/// Returns the current retry interval in seconds set for exponential backoff for the Realtime
96+
/// service.
97+
@property(nonatomic, readwrite, assign) double realtimeExponentialBackoffRetryInterval;
98+
/// Returns the time in seconds until the next request is allowed while in exponential backoff mode
99+
/// for the Realtime service.
100+
@property(nonatomic, readonly, assign) NSTimeInterval realtimeExponentialBackoffThrottleEndTime;
101+
/// Realtime connection attempts.
102+
@property(nonatomic, readwrite, assign) int realtimeRetryCount;
93103

94104
#pragma mark Throttling Methods
95105

@@ -113,12 +123,21 @@
113123

114124
/// Updates the metadata table with the current fetch status.
115125
/// @param fetchSuccess True if fetch was successful.
116-
- (void)updateMetadataWithFetchSuccessStatus:(BOOL)fetchSuccess;
126+
- (void)updateMetadataWithFetchSuccessStatus:(BOOL)fetchSuccess
127+
templateVersion:(NSString *)templateVersion;
117128

118129
/// Increases the throttling time. Should only be called if the fetch error indicates a server
119130
/// issue.
120131
- (void)updateExponentialBackoffTime;
121132

133+
/// Increases the throttling time for Realtime. Should only be called if the Realtime error
134+
/// indicates a server issue.
135+
- (void)updateRealtimeExponentialBackoffTime;
136+
137+
/// Returns the difference between the Realtime backoff end time and the current time in a
138+
/// NSTimeInterval format.
139+
- (NSTimeInterval)getRealtimeBackoffInterval;
140+
122141
/// Returns true if we are in exponential backoff mode and it is not yet the next request time.
123142
- (BOOL)shouldThrottle;
124143

FirebaseRemoteConfig/Sources/Public/FirebaseRemoteConfig/FIRRemoteConfig.h

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,23 @@ extern NSString *const _Nonnull FIRNamespaceGoogleMobilePlatform NS_SWIFT_NAME(
3030
extern NSString *const _Nonnull FIRRemoteConfigThrottledEndTimeInSecondsKey NS_SWIFT_NAME(
3131
RemoteConfigThrottledEndTimeInSecondsKey);
3232

33+
/**
34+
* Listener registration returned by `addOnConfigUpdateListener`. Calling its method `remove` stops
35+
* the listener from receiving config updates and unregisters itself.
36+
*
37+
* If remove is called and no other listener registrations remain, the connection to the real-time
38+
* RC backend is closed. Subsequently calling `addOnConfigUpdateListener` will re-open the
39+
* connection.
40+
*/
41+
NS_SWIFT_NAME(ConfigUpdateListenerRegistration)
42+
@interface FIRConfigUpdateListenerRegistration : NSObject
43+
/**
44+
* Removes the listener being tracked by this `ConfigUpdateListenerRegistration`. After the initial
45+
* call, subsequent calls have no effect.
46+
*/
47+
- (void)remove;
48+
@end
49+
3350
/// Indicates whether updated data was successfully fetched.
3451
typedef NS_ENUM(NSInteger, FIRRemoteConfigFetchStatus) {
3552
/// Config has never been fetched.
@@ -65,6 +82,20 @@ typedef NS_ERROR_ENUM(FIRRemoteConfigErrorDomain, FIRRemoteConfigError){
6582
FIRRemoteConfigErrorInternalError = 8003,
6683
} NS_SWIFT_NAME(RemoteConfigError);
6784

85+
/// Remote Config error domain that handles errors for the real-time service.
86+
extern NSString *const _Nonnull FIRRemoteConfigUpdateErrorDomain NS_SWIFT_NAME(RemoteConfigUpdateErrorDomain);
87+
/// Firebase Remote Config real-time service error.
88+
typedef NS_ERROR_ENUM(FIRRemoteConfigUpdateErrorDomain, FIRRemoteConfigUpdateError){
89+
/// Unable to make a connection to the backend.
90+
FIRRemoteConfigUpdateErrorStreamError = 8001,
91+
/// Unable to fetch the latest config.
92+
FIRRemoteConfigUpdateErrorNotFetched = 8002,
93+
/// The ConfigUpdate message was unparsable.
94+
FIRRemoteConfigUpdateErrorMessageInvalid = 8003,
95+
/// The real-time Remote Config service is unavailable.
96+
FIRRemoteConfigUpdateErrorUnavailable = 8004,
97+
} NS_SWIFT_NAME(RemoteConfigUpdateError);
98+
6899
/// Enumerated value that indicates the source of Remote Config data. Data can come from
69100
/// the Remote Config service, the DefaultConfig that is available when the app is first installed,
70101
/// or a static initialized value if data is not available from the service or DefaultConfig.
@@ -139,6 +170,17 @@ NS_SWIFT_NAME(RemoteConfigSettings)
139170
@property(nonatomic, assign) NSTimeInterval fetchTimeout;
140171
@end
141172

173+
#pragma mark - FIRRemoteConfigUpdate
174+
/// Firebase Remote Config update
175+
NS_SWIFT_NAME(RemoteConfigUpdate)
176+
@interface FIRRemoteConfigUpdate : NSObject
177+
178+
/// Parameter keys whose values have been updated from the currently activated values. Includes
179+
/// keys that are added, deleted, and whose value, value source, or metadata has changed.
180+
@property(nonatomic, readonly, nonnull) NSSet<NSString *> *updatedKeys;
181+
182+
@end
183+
142184
#pragma mark - FIRRemoteConfig
143185
/// Firebase Remote Config class. The class method `remoteConfig()` can be used
144186
/// to fetch, activate and read config results and set default config results on the default
@@ -283,4 +325,34 @@ NS_SWIFT_NAME(RemoteConfig)
283325
/// nil if the key doesn't exist in the default config.
284326
- (nullable FIRRemoteConfigValue *)defaultValueForKey:(nullable NSString *)key;
285327

328+
#pragma mark - Realtime
329+
330+
/// Completion handler invoked by `addOnConfigUpdateListener` when there is an update to
331+
/// the config from the backend.
332+
///
333+
/// @param configUpdate Information on which key's values have changed
334+
/// @param error Error message on failure.
335+
typedef void (^FIRRemoteConfigUpdateCompletion)(FIRRemoteConfigUpdate *_Nullable configUpdate,
336+
NSError *_Nullable error)
337+
NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead.");
338+
339+
/// Start listening for real-time config updates from the Remote Config backend and automatically
340+
/// fetch updates when they're available.
341+
///
342+
/// If a connection to the Remote Config backend is not already open, calling this method will
343+
/// open it. Multiple listeners can be added by calling this method again, but subsequent calls
344+
/// re-use the same connection to the backend.
345+
///
346+
/// Note: Real-time Remote Config requires the Firebase Remote Config Realtime API. See Get started
347+
/// with Firebase Remote Config at https://firebase.google.com/docs/remote-config/get-started for
348+
/// more information.
349+
///
350+
/// @param listener The configured listener that is called for every config update.
351+
/// @return Returns a registration representing the listener. The registration contains
352+
/// a remove method, which can be used to stop receiving for updates for this particular
353+
/// registration.
354+
- (FIRConfigUpdateListenerRegistration *_Nonnull)addOnConfigUpdateListener:
355+
(FIRRemoteConfigUpdateCompletion _Nonnull)listener
356+
NS_SWIFT_NAME(addOnConfigUpdateListener(remoteConfigUpdateCompletion:));
357+
286358
@end

FirebaseRemoteConfig/Sources/RCNConfigConstants.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,5 @@ static NSString *const RCNFetchResponseKeyStateNoTemplate = @"NO_TEMPLATE";
5858
static NSString *const RCNFetchResponseKeyStateNoChange = @"NO_CHANGE";
5959
/// Template found, but evaluates to empty (e.g. all keys omitted).
6060
static NSString *const RCNFetchResponseKeyStateEmptyConfig = @"EMPTY_CONFIG";
61+
/// Template Version key
62+
static NSString *const RCNFetchResponseKeyTemplateVersion = @"templateVersion";

FirebaseRemoteConfig/Sources/RCNConfigContent.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
#import <Foundation/Foundation.h>
1818

19+
#import "FirebaseRemoteConfig/Sources/Public/FirebaseRemoteConfig/FIRRemoteConfig.h"
20+
1921
typedef NS_ENUM(NSInteger, RCNDBSource) {
2022
RCNDBSourceActive,
2123
RCNDBSourceDefault,
@@ -63,4 +65,7 @@ typedef NS_ENUM(NSInteger, RCNDBSource) {
6365
/// Gets the active config and Personalization metadata.
6466
- (NSDictionary *)getConfigAndMetadataForNamespace:(NSString *)FIRNamespace;
6567

68+
/// Returns the updated parameters between fetched and active config.
69+
- (FIRRemoteConfigUpdate *)getConfigUpdateForNamespace:(NSString *)FIRNamespace;
70+
6671
@end

FirebaseRemoteConfig/Sources/RCNConfigContent.m

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#import "FirebaseRemoteConfig/Sources/RCNConfigContent.h"
1818

19+
#import "FirebaseRemoteConfig/Sources/Private/FIRRemoteConfig_Private.h"
1920
#import "FirebaseRemoteConfig/Sources/Public/FirebaseRemoteConfig/FIRRemoteConfig.h"
2021
#import "FirebaseRemoteConfig/Sources/RCNConfigConstants.h"
2122
#import "FirebaseRemoteConfig/Sources/RCNConfigDBManager.h"
@@ -363,6 +364,11 @@ - (NSDictionary *)defaultConfig {
363364
return _defaultConfig;
364365
}
365366

367+
- (NSDictionary *)activePersonalization {
368+
[self checkAndWaitForInitialDatabaseLoad];
369+
return _activePersonalization;
370+
}
371+
366372
- (NSDictionary *)getConfigAndMetadataForNamespace:(NSString *)FIRNamespace {
367373
/// If this is the first time reading the active metadata, we might still be reading it from the
368374
/// database.
@@ -392,4 +398,49 @@ - (BOOL)checkAndWaitForInitialDatabaseLoad {
392398
return true;
393399
}
394400

401+
// Compare fetched config with active config and output what has changed
402+
- (FIRRemoteConfigUpdate *)getConfigUpdateForNamespace:(NSString *)FIRNamespace {
403+
// TODO: handle diff in experiment metadata
404+
405+
FIRRemoteConfigUpdate *configUpdate;
406+
NSMutableSet<NSString *> *updatedKeys = [[NSMutableSet alloc] init];
407+
408+
NSDictionary *fetchedConfig =
409+
_fetchedConfig[FIRNamespace] ? _fetchedConfig[FIRNamespace] : [[NSDictionary alloc] init];
410+
NSDictionary *activeConfig =
411+
_activeConfig[FIRNamespace] ? _activeConfig[FIRNamespace] : [[NSDictionary alloc] init];
412+
NSDictionary *fetchedP13n = _fetchedPersonalization;
413+
NSDictionary *activeP13n = _activePersonalization;
414+
415+
// add new/updated params
416+
for (NSString *key in [fetchedConfig allKeys]) {
417+
if (activeConfig[key] == nil ||
418+
![[activeConfig[key] stringValue] isEqualToString:[fetchedConfig[key] stringValue]]) {
419+
[updatedKeys addObject:key];
420+
}
421+
}
422+
// add deleted params
423+
for (NSString *key in [activeConfig allKeys]) {
424+
if (fetchedConfig[key] == nil) {
425+
[updatedKeys addObject:key];
426+
}
427+
}
428+
429+
// add params with new/updated p13n metadata
430+
for (NSString *key in [fetchedP13n allKeys]) {
431+
if (activeP13n[key] == nil || ![activeP13n[key] isEqualToDictionary:fetchedP13n[key]]) {
432+
[updatedKeys addObject:key];
433+
}
434+
}
435+
// add params with deleted p13n metadata
436+
for (NSString *key in [activeP13n allKeys]) {
437+
if (fetchedP13n[key] == nil) {
438+
[updatedKeys addObject:key];
439+
}
440+
}
441+
442+
configUpdate = [[FIRRemoteConfigUpdate alloc] initWithUpdatedKeys:updatedKeys];
443+
return configUpdate;
444+
}
445+
395446
@end

0 commit comments

Comments
 (0)