Skip to content

Commit 90235b5

Browse files
authored
Reset RC per-instance userdefaults if config database was not found. (#4896)
* Reset the RC per-instance user defaults if the config database was not found. * Add unit test. * Ignore the non-object arguments when stubbing the fetchWithExpirationDuration method. * Update changelog.
1 parent 884455c commit 90235b5

File tree

8 files changed

+52
-1
lines changed

8 files changed

+52
-1
lines changed

FirebaseRemoteConfig/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# v4.4.8
2+
- [fixed] Fixed a bug (#4677, #4734) where Remote Config does not work after a restore of a previous backup of the device. (#4896).
13
# v4.4.7
24
- [fixed] Fixed a crash that could occur when attempting a remote config fetch before a valid Instance ID was available. (#4622)
35
- [fixed] Fixed an issue where config fetch would sometimes fail with a duplicate fetch error when no other fetches were in progress. (#3802)

FirebaseRemoteConfig/Sources/RCNConfigDBManager.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,4 +115,7 @@ typedef void (^RCNDBLoadCompletion)(BOOL success,
115115
/// Remove all the records from experiment table with given key.
116116
/// @param key The key of experiment data belongs to, which are defined in RCNConfigDefines.h.
117117
- (void)deleteExperimentTableForKey:(NSString *)key;
118+
119+
/// Returns true if this a new install of the Config database.
120+
- (BOOL)isNewDatabase;
118121
@end

FirebaseRemoteConfig/Sources/RCNConfigDBManager.m

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#define RCNTableNameInternalMetadata "internal_metadata"
3232
#define RCNTableNameExperiment "experiment"
3333

34+
static BOOL gIsNewDatabase;
3435
/// SQLite file name in versions 0, 1 and 2.
3536
static NSString *const RCNDatabaseName = @"RemoteConfig.sqlite3";
3637
/// The application support sub-directory that the Remote Config database resides in.
@@ -77,6 +78,7 @@ static BOOL RemoteConfigCreateFilePathIfNotExist(NSString *filePath) {
7778
}
7879
NSFileManager *fileManager = [NSFileManager defaultManager];
7980
if (![fileManager fileExistsAtPath:filePath]) {
81+
gIsNewDatabase = YES;
8082
NSError *error;
8183
[fileManager createDirectoryAtPath:[filePath stringByDeletingLastPathComponent]
8284
withIntermediateDirectories:YES
@@ -203,6 +205,7 @@ - (void)createOrOpenDatabase {
203205
NSString *dbPath = [RCNConfigDBManager remoteConfigPathForDatabase];
204206
FIRLogInfo(kFIRLoggerRemoteConfig, @"I-RCN000062", @"Loading database at path %@", dbPath);
205207
const char *databasePath = dbPath.UTF8String;
208+
206209
// Create or open database path.
207210
if (!RemoteConfigCreateFilePathIfNotExist(dbPath)) {
208211
return;
@@ -1036,4 +1039,8 @@ - (BOOL)logErrorWithSQL:(const char *)SQL
10361039
return returnValue;
10371040
}
10381041

1042+
- (BOOL)isNewDatabase {
1043+
return gIsNewDatabase;
1044+
}
1045+
10391046
@end

FirebaseRemoteConfig/Sources/RCNConfigSettings.m

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,14 @@ - (instancetype)initWithDatabaseManager:(RCNConfigDBManager *)manager
102102
_userDefaultsManager = [[RCNUserDefaultsManager alloc] initWithAppName:appName
103103
bundleID:_bundleIdentifier
104104
namespace:_FIRNamespace];
105+
106+
// Check if the config database is new. If so, clear the configs saved in userDefaults.
107+
if ([_DBManager isNewDatabase]) {
108+
FIRLogNotice(kFIRLoggerRemoteConfig, @"I-RCN000072",
109+
@"New config database created. Resetting user defaults.");
110+
[_userDefaultsManager resetUserDefaults];
111+
}
112+
105113
_isFetchInProgress = NO;
106114
}
107115
return self;

FirebaseRemoteConfig/Sources/RCNUserDefaultsManager.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ NS_ASSUME_NONNULL_BEGIN
4848
__attribute__((unavailable("Use `initWithAppName:bundleID:namespace:` instead.")));
4949
// NOLINTEND
5050

51+
/// Delete all saved userdefaults for this instance.
52+
- (void)resetUserDefaults;
5153
@end
5254

5355
NS_ASSUME_NONNULL_END

FirebaseRemoteConfig/Sources/RCNUserDefaultsManager.m

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,11 @@ - (void)setCurrentThrottlingRetryIntervalSeconds:(NSTimeInterval)throttlingRetry
174174
forKey:kRCNUserDefaultsKeyNamecurrentThrottlingRetryInterval];
175175
}
176176

177+
#pragma mark Public methods.
178+
- (void)resetUserDefaults {
179+
[self resetInstanceUserDefaults];
180+
}
181+
177182
#pragma mark Private methods.
178183

179184
// There is a nested hierarchy for the userdefaults as follows:
@@ -212,4 +217,17 @@ - (void)setInstanceUserDefaultsValue:(NSObject *)value forKey:(NSString *)key {
212217
}
213218
}
214219

220+
// Delete any existing userdefaults for this instance.
221+
- (void)resetInstanceUserDefaults {
222+
@synchronized(_userDefaults) {
223+
NSMutableDictionary *appUserDefaults = [[self appUserDefaults] mutableCopy];
224+
NSMutableDictionary *appNamespaceUserDefaults = [[self instanceUserDefaults] mutableCopy];
225+
[appNamespaceUserDefaults removeAllObjects];
226+
[appUserDefaults setObject:appNamespaceUserDefaults forKey:_firebaseNamespace];
227+
[_userDefaults setObject:appUserDefaults forKey:_firebaseAppName];
228+
// We need to synchronize to have this value updated for the extension.
229+
[_userDefaults synchronize];
230+
}
231+
}
232+
215233
@end

FirebaseRemoteConfig/Tests/Unit/RCNRemoteConfigTest.m

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,8 @@ - (void)setUp {
192192
namespace:fullyQualifiedNamespace
193193
options:currentOptions]);
194194

195-
OCMStub([_configFetch[i] fetchConfigWithExpirationDuration:43200 completionHandler:OCMOCK_ANY])
195+
OCMStub([_configFetch[i] fetchConfigWithExpirationDuration:0 completionHandler:OCMOCK_ANY])
196+
.ignoringNonObjectArgs()
196197
.andDo(^(NSInvocation *invocation) {
197198
void (^handler)(FIRRemoteConfigFetchStatus status, NSError *_Nullable error) = nil;
198199
[invocation getArgument:&handler atIndex:3];

FirebaseRemoteConfig/Tests/Unit/RCNUserDefaultsManagerTests.m

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,4 +170,14 @@ - (void)testUserDefaultsForMultipleNamespaces {
170170
RCNUserDefaultsSampleTimeStamp - 2.0);
171171
}
172172

173+
- (void)testUserDefaultsReset {
174+
RCNUserDefaultsManager* manager =
175+
[[RCNUserDefaultsManager alloc] initWithAppName:@"TESTING"
176+
bundleID:[NSBundle mainBundle].bundleIdentifier
177+
namespace:@"testNamespace1"];
178+
[manager setLastETag:@"testETag"];
179+
[manager resetUserDefaults];
180+
XCTAssertNil([manager lastETag]);
181+
}
182+
173183
@end

0 commit comments

Comments
 (0)