Skip to content

Commit ed0d3e8

Browse files
Merge pull request #35 from mparticle-integrations/fix/SDKE-146-i-os-ga-kit-fix-consent-mapping-configuration
fix: Consent Mapping Configuration
2 parents a269c62 + 7c1fc43 commit ed0d3e8

File tree

1 file changed

+101
-67
lines changed

1 file changed

+101
-67
lines changed

mParticle-Google-Analytics-Firebase/MPKitFirebaseAnalytics.m

Lines changed: 101 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,13 @@ @implementation MPKitFirebaseAnalytics
4242
static NSString *const aToZCharacters = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
4343
static NSString *const instanceIdIntegrationKey = @"app_instance_id";
4444

45-
static NSString *const kMPFIRGA4AdStorageKey = @"ad_storage";
46-
static NSString *const kMPFIRGA4AdUserDataKey = @"ad_user_data";
47-
static NSString *const kMPFIRGA4AdPersonalizationKey = @"ad_personalization";
48-
static NSString *const kMPFIRGA4AnalyticsStorageKey = @"analytics_storage";
45+
// Consent Mapping Keys
46+
static NSString *const kMPFIRGAAdStorageKey = @"ad_storage";
47+
static NSString *const kMPFIRGAAdUserDataKey = @"ad_user_data";
48+
static NSString *const kMPFIRGAAdPersonalizationKey = @"ad_personalization";
49+
static NSString *const kMPFIRGAAnalyticsStorageKey = @"analytics_storage";
50+
51+
// Default Consent Keys (from mParticle UI)
4952
static NSString *const kMPFIRGA4DefaultAdStorageKey = @"defaultAdStorageConsentSDK";
5053
static NSString *const kMPFIRGA4DefaultAdUserDataKey = @"defaultAdUserDataConsentSDK";
5154
static NSString *const kMPFIRGA4DefaultAdPersonalizationKey = @"defaultAdPersonalizationConsentSDK";
@@ -359,77 +362,52 @@ - (MPKitExecStatus *)setConsentState:(nullable MPConsentState *)state {
359362
}
360363

361364
- (void)updateConsent {
362-
FIRConsentStatus adStorageStatus;
363-
FIRConsentStatus adUserDataStatus;
364-
FIRConsentStatus analyticsStorageStatus;
365-
FIRConsentStatus adPersonalizationStatus;
366-
367-
// Default Consent States
368-
if (self.configuration[kMPFIRGA4DefaultAdStorageKey]) {
369-
if ([self.configuration[kMPFIRGA4DefaultAdStorageKey] isEqual: @"Granted"]) {
370-
adStorageStatus = FIRConsentStatusGranted;
371-
} else if ([self.configuration[kMPFIRGA4DefaultAdStorageKey] isEqual: @"Denied"]) {
372-
adStorageStatus = FIRConsentStatusDenied;
373-
}
374-
}
375-
if (self.configuration[kMPFIRGA4DefaultAdUserDataKey]) {
376-
if ([self.configuration[kMPFIRGA4DefaultAdUserDataKey] isEqual: @"Granted"]) {
377-
adUserDataStatus = FIRConsentStatusGranted;
378-
} else if ([self.configuration[kMPFIRGA4DefaultAdUserDataKey] isEqual: @"Denied"]) {
379-
adUserDataStatus = FIRConsentStatusDenied;
380-
}
381-
}
382-
if (self.configuration[kMPFIRGA4DefaultAnalyticsStorageKey]) {
383-
if ([self.configuration[kMPFIRGA4DefaultAnalyticsStorageKey] isEqual: @"Granted"]) {
384-
analyticsStorageStatus = FIRConsentStatusGranted;
385-
} else if ([self.configuration[kMPFIRGA4DefaultAnalyticsStorageKey] isEqual: @"Denied"]) {
386-
analyticsStorageStatus = FIRConsentStatusDenied;
387-
}
365+
NSArray<NSDictionary *> *mappings = [self mappingForKey: @"consentMappingSDK"];
366+
NSDictionary<NSString *, NSString *> *mappingsConfig;
367+
if (mappings != nil) {
368+
mappingsConfig = [self convertToKeyValuePairs: mappings];
388369
}
389-
if (self.configuration[kMPFIRGA4DefaultAdPersonalizationKey]) {
390-
if ([self.configuration[kMPFIRGA4DefaultAdPersonalizationKey] isEqual: @"Granted"]) {
391-
adPersonalizationStatus = FIRConsentStatusGranted;
392-
} else if ([self.configuration[kMPFIRGA4DefaultAdPersonalizationKey] isEqual: @"Denied"]) {
393-
adPersonalizationStatus = FIRConsentStatusDenied;
394-
}
395-
}
396-
370+
371+
397372
MParticleUser *currentUser = [[[MParticle sharedInstance] identity] currentUser];
398-
NSDictionary<NSString *, MPGDPRConsent *> *userConsentMap = currentUser.consentState.gdprConsentState;
373+
NSDictionary<NSString *, MPGDPRConsent *> *gdprConsents = currentUser.consentState.gdprConsentState;
399374

400-
// Update from mParticle consent
401-
if (self.configuration[kMPFIRGA4AdStorageKey] && userConsentMap[self.configuration[kMPFIRGA4AdStorageKey]]) {
402-
MPGDPRConsent *consent = userConsentMap[self.configuration[kMPFIRGA4AdStorageKey]];
403-
adStorageStatus = consent.consented ? FIRConsentStatusGranted : FIRConsentStatusDenied;
404-
}
405-
if (self.configuration[kMPFIRGA4AdUserDataKey] && userConsentMap[self.configuration[kMPFIRGA4AdUserDataKey]]) {
406-
MPGDPRConsent *consent = userConsentMap[self.configuration[kMPFIRGA4AdUserDataKey]];
407-
adUserDataStatus = consent.consented ? FIRConsentStatusGranted : FIRConsentStatusDenied;
408-
}
409-
if (self.configuration[kMPFIRGA4AnalyticsStorageKey] && userConsentMap[self.configuration[kMPFIRGA4AnalyticsStorageKey]]) {
410-
MPGDPRConsent *consent = userConsentMap[self.configuration[kMPFIRGA4AnalyticsStorageKey]];
411-
analyticsStorageStatus = consent.consented ? FIRConsentStatusGranted : FIRConsentStatusDenied;
412-
}
413-
if (self.configuration[kMPFIRGA4AdPersonalizationKey] && userConsentMap[self.configuration[kMPFIRGA4AdPersonalizationKey]]) {
414-
MPGDPRConsent *consent = userConsentMap[self.configuration[kMPFIRGA4AdPersonalizationKey]];
415-
adPersonalizationStatus = consent.consented ? FIRConsentStatusGranted : FIRConsentStatusDenied;
416-
}
375+
NSNumber *adStorage = [self resolvedConsentForMappingKey:kMPFIRGAAdStorageKey
376+
defaultKey:kMPFIRGA4DefaultAdStorageKey
377+
gdprConsents:gdprConsents
378+
mapping:mappingsConfig];
379+
380+
NSNumber *adUserData = [self resolvedConsentForMappingKey:kMPFIRGAAdUserDataKey
381+
defaultKey:kMPFIRGA4DefaultAdUserDataKey
382+
gdprConsents:gdprConsents
383+
mapping:mappingsConfig];
417384

418-
// Construct a dictionary of consents
419-
NSMutableDictionary *uploadDict = [[NSMutableDictionary alloc] init];
420-
if (adStorageStatus) {
421-
uploadDict[FIRConsentTypeAdStorage] = adStorageStatus;
385+
NSNumber *analyticsStorage = [self resolvedConsentForMappingKey:kMPFIRGAAnalyticsStorageKey
386+
defaultKey:kMPFIRGA4DefaultAnalyticsStorageKey
387+
gdprConsents:gdprConsents
388+
mapping:mappingsConfig];
389+
390+
NSNumber *adPersonalization = [self resolvedConsentForMappingKey:kMPFIRGAAdPersonalizationKey
391+
defaultKey:kMPFIRGA4DefaultAdPersonalizationKey
392+
gdprConsents:gdprConsents
393+
mapping:mappingsConfig];
394+
395+
NSMutableDictionary *uploadDict = [NSMutableDictionary dictionary];
396+
397+
if (adStorage != nil) {
398+
uploadDict[FIRConsentTypeAdStorage] = adStorage.boolValue ? FIRConsentStatusGranted : FIRConsentStatusDenied;
422399
}
423-
if (adUserDataStatus) {
424-
uploadDict[FIRConsentTypeAdUserData] = adUserDataStatus;
400+
if (adUserData != nil) {
401+
uploadDict[FIRConsentTypeAdUserData] = adUserData.boolValue ? FIRConsentStatusGranted : FIRConsentStatusDenied;
425402
}
426-
if (analyticsStorageStatus) {
427-
uploadDict[FIRConsentTypeAnalyticsStorage] = analyticsStorageStatus;
403+
if (analyticsStorage != nil) {
404+
uploadDict[FIRConsentTypeAnalyticsStorage] = analyticsStorage.boolValue ? FIRConsentStatusGranted : FIRConsentStatusDenied;
428405
}
429-
if (adPersonalizationStatus) {
430-
uploadDict[FIRConsentTypeAdPersonalization] = adPersonalizationStatus;
406+
if (adPersonalization != nil) {
407+
uploadDict[FIRConsentTypeAdPersonalization] = adPersonalization.boolValue ? FIRConsentStatusGranted : FIRConsentStatusDenied;
431408
}
432-
409+
410+
433411
// Update consent state with FIRAnalytics
434412
[FIRAnalytics setConsent:uploadDict];
435413
}
@@ -654,4 +632,60 @@ - (void)updateInstanceIDIntegration {
654632
}
655633
}
656634

635+
#pragma mark - Helpers
636+
637+
- (NSNumber * _Nullable)resolvedConsentForMappingKey:(NSString *)mappingKey
638+
defaultKey:(NSString *)defaultKey
639+
gdprConsents:(NSDictionary<NSString *, MPGDPRConsent *> *)gdprConsents
640+
mapping:(NSDictionary<NSString *, NSString*> *) mapping {
641+
642+
// Prefer mParticle Consent if available
643+
NSString *purpose = mapping[mappingKey];
644+
if (purpose) {
645+
MPGDPRConsent *consent = gdprConsents[purpose];
646+
if (consent) {
647+
return @(consent.consented);
648+
}
649+
}
650+
651+
// Fallback to configuration defaults
652+
NSString *value = self->_configuration[defaultKey];
653+
if ([value isEqualToString:@"Granted"]) {
654+
return @(YES);
655+
} else if ([value isEqualToString:@"Denied"]) {
656+
return @(NO);
657+
}
658+
return nil;
659+
}
660+
661+
- (NSArray<NSDictionary *>*)mappingForKey:(NSString*)key {
662+
NSString *mappingJson = _configuration[@"consentMappingSDK"];
663+
if (![mappingJson isKindOfClass:[NSString class]]) {
664+
return nil;
665+
}
666+
667+
NSData *jsonData = [mappingJson dataUsingEncoding:NSUTF8StringEncoding];
668+
NSError *error;
669+
NSArray *result = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error];
670+
671+
if (error) {
672+
NSLog(@"Failed to parse consent mapping JSON: %@", error.localizedDescription);
673+
return nil;
674+
}
675+
676+
return result;
677+
}
678+
679+
- (NSDictionary*)convertToKeyValuePairs: (NSArray<NSDictionary *>*) mappings {
680+
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
681+
for (NSDictionary *entry in mappings) {
682+
NSString *value = entry[@"value"];
683+
NSString *purpose = [entry[@"map"] lowercaseString];
684+
if (value && purpose) {
685+
dict[value] = purpose;
686+
}
687+
}
688+
return dict;
689+
}
690+
657691
@end

0 commit comments

Comments
 (0)