@@ -44,10 +44,13 @@ @implementation MPKitFirebaseGA4Analytics
44
44
static NSString *const instanceIdIntegrationKey = @" app_instance_id" ;
45
45
static NSString *const invalidFirebaseKey = @" invalid_ga4_key" ;
46
46
47
+ // Consent Mapping Keys
47
48
static NSString *const kMPFIRGA4AdStorageKey = @" ad_storage" ;
48
49
static NSString *const kMPFIRGA4AdUserDataKey = @" ad_user_data" ;
49
50
static NSString *const kMPFIRGA4AdPersonalizationKey = @" ad_personalization" ;
50
51
static NSString *const kMPFIRGA4AnalyticsStorageKey = @" analytics_storage" ;
52
+
53
+ // Default Consent Keys (from mParticle UI)
51
54
static NSString *const kMPFIRGA4DefaultAdStorageKey = @" defaultAdStorageConsentSDK" ;
52
55
static NSString *const kMPFIRGA4DefaultAdUserDataKey = @" defaultAdUserDataConsentSDK" ;
53
56
static NSString *const kMPFIRGA4DefaultAdPersonalizationKey = @" defaultAdPersonalizationConsentSDK" ;
@@ -385,76 +388,51 @@ - (MPKitExecStatus *)setConsentState:(nullable MPConsentState *)state {
385
388
}
386
389
387
390
- (void )updateConsent {
388
- FIRConsentStatus adStorageStatus;
389
- FIRConsentStatus adUserDataStatus;
390
- FIRConsentStatus analyticsStorageStatus;
391
- FIRConsentStatus adPersonalizationStatus;
392
-
393
- // Default Consent States
394
- if (self.configuration [kMPFIRGA4DefaultAdStorageKey ]) {
395
- if ([self .configuration[kMPFIRGA4DefaultAdStorageKey ] isEqual: @" Granted" ]) {
396
- adStorageStatus = FIRConsentStatusGranted;
397
- } else if ([self .configuration[kMPFIRGA4DefaultAdStorageKey ] isEqual: @" Denied" ]) {
398
- adStorageStatus = FIRConsentStatusDenied;
399
- }
400
- }
401
- if (self.configuration [kMPFIRGA4DefaultAdUserDataKey ]) {
402
- if ([self .configuration[kMPFIRGA4DefaultAdUserDataKey ] isEqual: @" Granted" ]) {
403
- adUserDataStatus = FIRConsentStatusGranted;
404
- } else if ([self .configuration[kMPFIRGA4DefaultAdUserDataKey ] isEqual: @" Denied" ]) {
405
- adUserDataStatus = FIRConsentStatusDenied;
406
- }
407
- }
408
- if (self.configuration [kMPFIRGA4DefaultAnalyticsStorageKey ]) {
409
- if ([self .configuration[kMPFIRGA4DefaultAnalyticsStorageKey ] isEqual: @" Granted" ]) {
410
- analyticsStorageStatus = FIRConsentStatusGranted;
411
- } else if ([self .configuration[kMPFIRGA4DefaultAnalyticsStorageKey ] isEqual: @" Denied" ]) {
412
- analyticsStorageStatus = FIRConsentStatusDenied;
413
- }
414
- }
415
- if (self.configuration [kMPFIRGA4DefaultAdPersonalizationKey ]) {
416
- if ([self .configuration[kMPFIRGA4DefaultAdPersonalizationKey ] isEqual: @" Granted" ]) {
417
- adPersonalizationStatus = FIRConsentStatusGranted;
418
- } else if ([self .configuration[kMPFIRGA4DefaultAdPersonalizationKey ] isEqual: @" Denied" ]) {
419
- adPersonalizationStatus = FIRConsentStatusDenied;
420
- }
391
+ NSArray <NSDictionary *> *mappings = [self mappingForKey: @" consentMappingSDK" ];
392
+ NSDictionary <NSString *, NSString *> *mappingsConfig;
393
+ if (mappings != nil ) {
394
+ mappingsConfig = [self convertToKeyValuePairs: mappings];
421
395
}
422
396
423
- MParticleUser *currentUser = [[[MParticle sharedInstance ] identity ] currentUser ];
424
- NSDictionary <NSString *, MPGDPRConsent *> *userConsentMap = currentUser.consentState .gdprConsentState ;
425
397
426
- // Update from mParticle consent
427
- if (self.configuration [kMPFIRGA4AdStorageKey ] && userConsentMap[self .configuration[kMPFIRGA4AdStorageKey ]]) {
428
- MPGDPRConsent *consent = userConsentMap[self .configuration[kMPFIRGA4AdStorageKey ]];
429
- adStorageStatus = consent.consented ? FIRConsentStatusGranted : FIRConsentStatusDenied;
398
+ MParticleUser *currentUser = [[[MParticle sharedInstance ] identity ] currentUser ];
399
+ NSDictionary <NSString *, MPGDPRConsent *> *gdprConsents = currentUser.consentState .gdprConsentState ;
400
+
401
+ NSNumber *adStorage = [self resolvedConsentForMappingKey: kMPFIRGA4AdStorageKey
402
+ defaultKey: kMPFIRGA4DefaultAdStorageKey
403
+ gdprConsents: gdprConsents
404
+ mapping: mappingsConfig];
405
+
406
+ NSNumber *adUserData = [self resolvedConsentForMappingKey: kMPFIRGA4AdUserDataKey
407
+ defaultKey: kMPFIRGA4DefaultAdUserDataKey
408
+ gdprConsents: gdprConsents
409
+ mapping: mappingsConfig];
410
+
411
+ NSNumber *analyticsStorage = [self resolvedConsentForMappingKey: kMPFIRGA4AnalyticsStorageKey
412
+ defaultKey: kMPFIRGA4DefaultAnalyticsStorageKey
413
+ gdprConsents: gdprConsents
414
+ mapping: mappingsConfig];
415
+
416
+ NSNumber *adPersonalization = [self resolvedConsentForMappingKey: kMPFIRGA4AdPersonalizationKey
417
+ defaultKey: kMPFIRGA4DefaultAdPersonalizationKey
418
+ gdprConsents: gdprConsents
419
+ mapping: mappingsConfig];
420
+
421
+ NSMutableDictionary *uploadDict = [NSMutableDictionary dictionary ];
422
+
423
+ if (adStorage != nil ) {
424
+ uploadDict[FIRConsentTypeAdStorage] = adStorage.boolValue ? FIRConsentStatusGranted : FIRConsentStatusDenied;
430
425
}
431
- if (self.configuration [kMPFIRGA4AdUserDataKey ] && userConsentMap[self .configuration[kMPFIRGA4AdUserDataKey ]]) {
432
- MPGDPRConsent *consent = userConsentMap[self .configuration[kMPFIRGA4AdUserDataKey ]];
433
- adUserDataStatus = consent.consented ? FIRConsentStatusGranted : FIRConsentStatusDenied;
426
+ if (adUserData != nil ) {
427
+ uploadDict[FIRConsentTypeAdUserData] = adUserData.boolValue ? FIRConsentStatusGranted : FIRConsentStatusDenied;
434
428
}
435
- if (self.configuration [kMPFIRGA4AnalyticsStorageKey ] && userConsentMap[self .configuration[kMPFIRGA4AnalyticsStorageKey ]]) {
436
- MPGDPRConsent *consent = userConsentMap[self .configuration[kMPFIRGA4AnalyticsStorageKey ]];
437
- analyticsStorageStatus = consent.consented ? FIRConsentStatusGranted : FIRConsentStatusDenied;
429
+ if (analyticsStorage != nil ) {
430
+ uploadDict[FIRConsentTypeAnalyticsStorage] = analyticsStorage.boolValue ? FIRConsentStatusGranted : FIRConsentStatusDenied;
438
431
}
439
- if (self.configuration [kMPFIRGA4AdPersonalizationKey ] && userConsentMap[self .configuration[kMPFIRGA4AdPersonalizationKey ]]) {
440
- MPGDPRConsent *consent = userConsentMap[self .configuration[kMPFIRGA4AdPersonalizationKey ]];
441
- adPersonalizationStatus = consent.consented ? FIRConsentStatusGranted : FIRConsentStatusDenied;
432
+ if (adPersonalization != nil ) {
433
+ uploadDict[FIRConsentTypeAdPersonalization] = adPersonalization.boolValue ? FIRConsentStatusGranted : FIRConsentStatusDenied;
442
434
}
443
435
444
- // Construct a dictionary of consents
445
- NSMutableDictionary *uploadDict = [[NSMutableDictionary alloc ] init ];
446
- if (adStorageStatus) {
447
- uploadDict[FIRConsentTypeAdStorage] = adStorageStatus;
448
- }
449
- if (adUserDataStatus) {
450
- uploadDict[FIRConsentTypeAdUserData] = adUserDataStatus;
451
- }
452
- if (analyticsStorageStatus) {
453
- uploadDict[FIRConsentTypeAnalyticsStorage] = analyticsStorageStatus;
454
- }
455
- if (adPersonalizationStatus) {
456
- uploadDict[FIRConsentTypeAdPersonalization] = adPersonalizationStatus;
457
- }
458
436
459
437
// Update consent state with FIRAnalytics
460
438
[FIRAnalytics setConsent: uploadDict];
@@ -688,4 +666,60 @@ - (void)limitDictionary:(NSMutableDictionary *)dictionary maxCount:(int)maxCount
688
666
}
689
667
}
690
668
669
+ #pragma mark - Helpers
670
+
671
+ - (NSNumber * _Nullable)resolvedConsentForMappingKey : (NSString *)mappingKey
672
+ defaultKey : (NSString *)defaultKey
673
+ gdprConsents : (NSDictionary <NSString *, MPGDPRConsent *> *)gdprConsents
674
+ mapping : (NSDictionary <NSString *, NSString*> *) mapping {
675
+
676
+ // Prefer mParticle Consent if available
677
+ NSString *purpose = mapping[mappingKey];
678
+ if (purpose) {
679
+ MPGDPRConsent *consent = gdprConsents[purpose];
680
+ if (consent) {
681
+ return @(consent.consented );
682
+ }
683
+ }
684
+
685
+ // Fallback to configuration defaults
686
+ NSString *value = self->_configuration [defaultKey];
687
+ if ([value isEqualToString: @" Granted" ]) {
688
+ return @(YES );
689
+ } else if ([value isEqualToString: @" Denied" ]) {
690
+ return @(NO );
691
+ }
692
+ return nil ;
693
+ }
694
+
695
+ - (NSArray <NSDictionary *>*)mappingForKey : (NSString *)key {
696
+ NSString *mappingJson = _configuration[@" consentMappingSDK" ];
697
+ if (![mappingJson isKindOfClass: [NSString class ]]) {
698
+ return nil ;
699
+ }
700
+
701
+ NSData *jsonData = [mappingJson dataUsingEncoding: NSUTF8StringEncoding];
702
+ NSError *error;
703
+ NSArray *result = [NSJSONSerialization JSONObjectWithData: jsonData options: 0 error: &error];
704
+
705
+ if (error) {
706
+ NSLog (@" Failed to parse consent mapping JSON: %@ " , error.localizedDescription );
707
+ return nil ;
708
+ }
709
+
710
+ return result;
711
+ }
712
+
713
+ - (NSDictionary *)convertToKeyValuePairs : (NSArray <NSDictionary *>*) mappings {
714
+ NSMutableDictionary *dict = [NSMutableDictionary dictionary ];
715
+ for (NSDictionary *entry in mappings) {
716
+ NSString *value = entry[@" value" ];
717
+ NSString *purpose = [entry[@" map" ] lowercaseString ];
718
+ if (value && purpose) {
719
+ dict[value] = purpose;
720
+ }
721
+ }
722
+ return dict;
723
+ }
724
+
691
725
@end
0 commit comments