New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add global data collection switch. #1219
Changes from 3 commits
8728d20
d98a71f
99c4e0c
9423978
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -46,6 +46,11 @@ | |
NSString *const kFIRAppNameKey = @"FIRAppNameKey"; | ||
NSString *const kFIRGoogleAppIDKey = @"FIRGoogleAppIDKey"; | ||
|
||
NSString *const kFIRGlobalAppDataCollectionEnabledDefaultsKeyFormat = | ||
@"/google/firebase/global_data_collection_enabled:%@"; | ||
NSString *const kFIRGlobalAppDataCollectionEnabledPlistKey = | ||
@"FirebaseAutomaticDataCollectionEnabled"; | ||
|
||
NSString *const kFIRAppDiagnosticsNotification = @"FIRAppDiagnosticsNotification"; | ||
|
||
NSString *const kFIRAppDiagnosticsConfigurationTypeKey = @"ConfigType"; | ||
|
@@ -227,6 +232,7 @@ - (void)deleteApp:(FIRAppVoidBoolCallback)completion { | |
if (sAllApps && sAllApps[self.name]) { | ||
FIRLogDebug(kFIRLoggerCore, @"I-COR000006", @"Deleting app named %@", self.name); | ||
[sAllApps removeObjectForKey:self.name]; | ||
[self clearDataCollectionSwitchFromUserDefaults]; | ||
if ([self.name isEqualToString:kFIRDefaultAppName]) { | ||
sDefaultApp = nil; | ||
} | ||
|
@@ -332,6 +338,30 @@ - (FIROptions *)options { | |
return [_options copy]; | ||
} | ||
|
||
- (void)setAutomaticDataCollectionEnabled:(BOOL)automaticDataCollectionEnabled { | ||
NSString *key = | ||
[NSString stringWithFormat:kFIRGlobalAppDataCollectionEnabledDefaultsKeyFormat, self.name]; | ||
[[NSUserDefaults standardUserDefaults] setBool:automaticDataCollectionEnabled forKey:key]; | ||
} | ||
|
||
- (BOOL)isAutomaticDataCollectionEnabled { | ||
// Check if it's been manually set before in code, and use that as the higher priority value. | ||
NSNumber *defaultsObject = [[self class] readDataCollectionSwitchFromUserDefaultsForApp:self]; | ||
if (defaultsObject) { | ||
return [defaultsObject boolValue]; | ||
} | ||
|
||
// Read the Info.plist to see if the flag is set. If it's not set, it should default to `YES`. | ||
// As per the implementation of `readDataCollectionSwitchFromPlist`, it's a cached value and has | ||
// no performance impact calling multiple times. | ||
NSNumber *collectionEnabledPlistValue = [[self class] readDataCollectionSwitchFromPlist]; | ||
if (collectionEnabledPlistValue) { | ||
return [collectionEnabledPlistValue boolValue]; | ||
} else { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: no need for else There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
return YES; | ||
} | ||
} | ||
|
||
#pragma mark - private | ||
|
||
+ (void)sendNotificationsToSDKs:(FIRApp *)app { | ||
|
@@ -613,11 +643,64 @@ - (NSString *)expectedBundleID { | |
} | ||
|
||
// end App ID validation | ||
#pragma mark | ||
|
||
#pragma mark - Reading From Plist & User Defaults | ||
|
||
/** | ||
* A wrapper to clear the data collection switch from the standard NSUserDefaults for easier testing | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: Clears the data collection ... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
* and readability. | ||
*/ | ||
- (void)clearDataCollectionSwitchFromUserDefaults { | ||
NSString *key = | ||
[NSString stringWithFormat:kFIRGlobalAppDataCollectionEnabledDefaultsKeyFormat, self.name]; | ||
[[NSUserDefaults standardUserDefaults] removeObjectForKey:key]; | ||
} | ||
|
||
/** | ||
* A wrapper to read the data collection switch from the standard NSUserDefaults for easier testing | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: Reads the data collection... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
* and readability. | ||
*/ | ||
+ (nullable NSNumber *)readDataCollectionSwitchFromUserDefaultsForApp:(FIRApp *)app { | ||
// Read the object in user defaults, and only return if it's an NSNumber. | ||
NSString *key = | ||
[NSString stringWithFormat:kFIRGlobalAppDataCollectionEnabledDefaultsKeyFormat, app.name]; | ||
id collectionEnabledDefaultsObject = [[NSUserDefaults standardUserDefaults] objectForKey:key]; | ||
if ([collectionEnabledDefaultsObject isKindOfClass:[NSNumber class]]) { | ||
return collectionEnabledDefaultsObject; | ||
} else { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: no need for else There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
return nil; | ||
} | ||
} | ||
|
||
/** | ||
* A wrapper to read the data collection switch from the Info.plist for easier testing and | ||
* readability. Will only read once from the plist and return the cached value. | ||
*/ | ||
+ (nullable NSNumber *)readDataCollectionSwitchFromPlist { | ||
static NSNumber *collectionEnabledPlistObject; | ||
static dispatch_once_t onceToken; | ||
dispatch_once(&onceToken, ^{ | ||
// Read the data from the `Info.plist`, only assign it if it's there and an NSNumber. | ||
id plistValue = [[NSBundle mainBundle] | ||
objectForInfoDictionaryKey:kFIRGlobalAppDataCollectionEnabledPlistKey]; | ||
if (plistValue && [plistValue isKindOfClass:[NSNumber class]]) { | ||
collectionEnabledPlistObject = (NSNumber *)plistValue; | ||
} | ||
}); | ||
|
||
return collectionEnabledPlistObject; | ||
} | ||
|
||
#pragma mark - Sending Logs | ||
|
||
- (void)sendLogsWithServiceName:(NSString *)serviceName | ||
version:(NSString *)version | ||
error:(NSError *)error { | ||
// If the user has manually turned off data collection, return and don't send logs. | ||
if (![self isAutomaticDataCollectionEnabled]) { | ||
return; | ||
} | ||
|
||
NSMutableDictionary *userInfo = [[NSMutableDictionary alloc] initWithDictionary:@{ | ||
kFIRAppDiagnosticsConfigurationTypeKey : @(FIRConfigTypeSDK), | ||
kFIRAppDiagnosticsSDKNameKey : serviceName, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -75,7 +75,7 @@ | |
|
||
NSString *const kFIRMessagingAPNSTokenType = @"APNSTokenType"; // APNS Token type key stored in user info. | ||
|
||
static NSString *const kFIRMessagingPlistAutoInitEnabled = | ||
NSString *const kFIRMessagingPlistAutoInitEnabled = | ||
@"FirebaseMessagingAutoInitEnabled"; // Auto Init Enabled key stored in Info.plist | ||
|
||
@interface FIRMessagingMessageInfo () | ||
|
@@ -471,8 +471,9 @@ - (BOOL)isAutoInitEnabled { | |
if (isAutoInitEnabledObject) { | ||
return [isAutoInitEnabledObject boolValue]; | ||
} | ||
// If none of above exists, we default assume FCM auto init is enabled. | ||
return YES; | ||
|
||
// If none of above exists, we default to the global switch that comes from FIRApp. | ||
return self.isGlobalAutomaticDataCollectionEnabled; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Before we make sure it's default true if no special action happened on the user side, so we make sure we are not breaking app's existing behavior on fetching instanceID, and other activities. Is this global boolean value also serves the same purpose, that if developer doesn't do anything, it will be default ture? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, if nothing is set in the plist or at runtime, the default is true and we have unit tests to confirm that. |
||
} | ||
|
||
- (void)setAutoInitEnabled:(BOOL)autoInitEnabled { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
self.name can be nil. We should check it before accessing the dictionary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We throw an exception if a user tries to configure the app with a
nil
or empty name, which should catch this. If you're still concerned, we can add it in a separate PR since it's unrelated to this change.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok. I think we should be careful of accessing dictionary when the provided key is nil. I'm concerned that self.name might be nil at some point during the entire app life cycle.