From a81c44f2fa21d0f8d26a562692b3f6e0467c91ec Mon Sep 17 00:00:00 2001 From: Brandon Stalnaker Date: Wed, 4 Sep 2024 09:25:41 -0400 Subject: [PATCH 1/3] feat: Implement Google EU Consent --- Sources/mParticle-Appboy/MPKitAppboy.m | 30 ++++++++++++++++++++++++++ mParticle-Appboy.podspec | 10 ++++----- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/Sources/mParticle-Appboy/MPKitAppboy.m b/Sources/mParticle-Appboy/MPKitAppboy.m index 18bf6db..65f0384 100644 --- a/Sources/mParticle-Appboy/MPKitAppboy.m +++ b/Sources/mParticle-Appboy/MPKitAppboy.m @@ -47,6 +47,12 @@ static NSString *const promotionKey = @"promotions"; static NSString *const impressionKey = @"impressions"; +// Strings used for Google Consent +static NSString *const MPGoogleAdUserDataKey = @"google_ad_user_data"; +static NSString *const MPGoogleAdPersonalizationKey = @"google_ad_personalization"; +static NSString *const BGoogleAdUserDataKey = @"$google_ad_user_data"; +static NSString *const BGoogleAdPersonalizationKey = @"$google_ad_personalization"; + #if TARGET_OS_IOS static id inAppMessageControllerDelegate = nil; static BOOL shouldDisableNotificationHandling = NO; @@ -325,6 +331,9 @@ - (MPKitExecStatus *)didFinishLaunchingWithConfiguration:(NSDictionary *)configu _started = NO; } + // Update Consent on launch + [self updateConsent]; + execStatus = [[MPKitExecStatus alloc] initWithSDKCode:[[self class] kitCode] returnCode:MPKitReturnCodeSuccess]; return execStatus; } @@ -1037,6 +1046,27 @@ - (MPKitExecStatus *)setATTStatus:(MPATTAuthorizationStatus)status withATTStatus return [[MPKitExecStatus alloc] initWithSDKCode:@(MPKitInstanceAppboy) returnCode:MPKitReturnCodeSuccess]; } +- (MPKitExecStatus *)setConsentState:(nullable MPConsentState *)state { + [self updateConsent]; + + return [[MPKitExecStatus alloc] initWithSDKCode:@(MPKitInstanceAppboy) returnCode:MPKitReturnCodeSuccess]; +} + +- (void)updateConsent { + MParticleUser *currentUser = [[[MParticle sharedInstance] identity] currentUser]; + NSDictionary *userConsentMap = currentUser.consentState.gdprConsentState; + + // Update from mParticle consent + if (self.configuration[MPGoogleAdUserDataKey] && userConsentMap[self.configuration[MPGoogleAdUserDataKey]]) { + MPGDPRConsent *consent = userConsentMap[self.configuration[MPGoogleAdUserDataKey]]; + [appboyInstance.user setCustomAttributeWithKey:BGoogleAdUserDataKey boolValue:consent.consented]; + } + if (self.configuration[MPGoogleAdPersonalizationKey] && userConsentMap[self.configuration[MPGoogleAdPersonalizationKey]]) { + MPGDPRConsent *consent = userConsentMap[self.configuration[MPGoogleAdPersonalizationKey]]; + [appboyInstance.user setCustomAttributeWithKey:BGoogleAdPersonalizationKey boolValue:consent.consented]; + } +} + #pragma mark Configuration Dictionary - (NSMutableDictionary *)simplifiedDictionary:(NSDictionary *)originalDictionary { diff --git a/mParticle-Appboy.podspec b/mParticle-Appboy.podspec index 7951b0e..fdd03ba 100755 --- a/mParticle-Appboy.podspec +++ b/mParticle-Appboy.podspec @@ -19,16 +19,16 @@ Pod::Spec.new do |s| s.ios.source_files = 'Sources/**/*.{h,m,mm}' s.ios.resource_bundles = { 'mParticle-Appboy-Privacy' => ['Sources/mParticle-Appboy/PrivacyInfo.xcprivacy'] } s.ios.dependency 'mParticle-Apple-SDK', '~> 8.19' - s.ios.dependency 'BrazeKit', '~> 9.0' - s.ios.dependency 'BrazeKitCompat', '~> 9.0' - s.ios.dependency 'BrazeUI', '~> 9.0' + s.ios.dependency 'BrazeKit', '~> 10.0' + s.ios.dependency 'BrazeKitCompat', '~> 10.0' + s.ios.dependency 'BrazeUI', '~> 10.0' s.tvos.deployment_target = "12.0" s.tvos.source_files = 'Sources/**/*.{h,m,mm}' s.tvos.resource_bundles = { 'mParticle-Appboy-Privacy' => ['Sources/mParticle-Appboy/PrivacyInfo.xcprivacy'] } s.tvos.dependency 'mParticle-Apple-SDK', '~> 8.19' - s.tvos.dependency 'BrazeKit', '~> 9.0' - s.tvos.dependency 'BrazeKitCompat', '~> 9.0' + s.tvos.dependency 'BrazeKit', '~> 10.0' + s.tvos.dependency 'BrazeKitCompat', '~> 10.0' end From 195a318ee499aae0e60a8989da74ff43ba7a331d Mon Sep 17 00:00:00 2001 From: Brandon Stalnaker Date: Fri, 6 Sep 2024 12:25:56 -0400 Subject: [PATCH 2/3] update logic --- Sources/mParticle-Appboy/MPKitAppboy.m | 33 +++++++++++++++++++------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/Sources/mParticle-Appboy/MPKitAppboy.m b/Sources/mParticle-Appboy/MPKitAppboy.m index 65f0384..0397bfb 100644 --- a/Sources/mParticle-Appboy/MPKitAppboy.m +++ b/Sources/mParticle-Appboy/MPKitAppboy.m @@ -48,6 +48,9 @@ static NSString *const impressionKey = @"impressions"; // Strings used for Google Consent +static NSString *const MPMapKey = @"map"; +static NSString *const MPValueKey = @"value"; +static NSString *const MPConsentMappingSDKKey = @"consentMappingSDK"; static NSString *const MPGoogleAdUserDataKey = @"google_ad_user_data"; static NSString *const MPGoogleAdPersonalizationKey = @"google_ad_personalization"; static NSString *const BGoogleAdUserDataKey = @"$google_ad_user_data"; @@ -1055,15 +1058,29 @@ - (MPKitExecStatus *)setConsentState:(nullable MPConsentState *)state { - (void)updateConsent { MParticleUser *currentUser = [[[MParticle sharedInstance] identity] currentUser]; NSDictionary *userConsentMap = currentUser.consentState.gdprConsentState; - + // Update from mParticle consent - if (self.configuration[MPGoogleAdUserDataKey] && userConsentMap[self.configuration[MPGoogleAdUserDataKey]]) { - MPGDPRConsent *consent = userConsentMap[self.configuration[MPGoogleAdUserDataKey]]; - [appboyInstance.user setCustomAttributeWithKey:BGoogleAdUserDataKey boolValue:consent.consented]; - } - if (self.configuration[MPGoogleAdPersonalizationKey] && userConsentMap[self.configuration[MPGoogleAdPersonalizationKey]]) { - MPGDPRConsent *consent = userConsentMap[self.configuration[MPGoogleAdPersonalizationKey]]; - [appboyInstance.user setCustomAttributeWithKey:BGoogleAdPersonalizationKey boolValue:consent.consented]; + if (self.configuration && self.configuration[MPConsentMappingSDKKey]) { + // Retrieve the array of Consent Map Dicitonaries from the Config + NSData *objectData = [self.configuration[MPConsentMappingSDKKey] dataUsingEncoding:NSUTF8StringEncoding]; + NSArray *consentMappingArray = [NSJSONSerialization JSONObjectWithData:objectData + options:NSJSONReadingMutableContainers + error:nil]; + + // For each valid Consent Map check if mParticle has a corresponding consent setting and, if so, send to Braze + for (NSDictionary *consentMappingDict in consentMappingArray) { + NSString *consentPurpose = consentMappingDict[MPMapKey]; + if (consentMappingDict[MPValueKey] && userConsentMap[consentPurpose.lowercaseString]) { + NSString *brazeConsentName = consentMappingDict[MPValueKey]; + MPGDPRConsent *consent = userConsentMap[consentPurpose.lowercaseString]; + if ([brazeConsentName isEqualToString:MPGoogleAdUserDataKey]) { + [appboyInstance.user setCustomAttributeWithKey:BGoogleAdUserDataKey boolValue:consent.consented]; + } + if ([brazeConsentName isEqualToString:MPGoogleAdPersonalizationKey]) { + [appboyInstance.user setCustomAttributeWithKey:BGoogleAdPersonalizationKey boolValue:consent.consented]; + } + } + } } } From 068a612a02c2be1cc4f496020cd61921c7d4454f Mon Sep 17 00:00:00 2001 From: Brandon Stalnaker Date: Mon, 9 Sep 2024 10:33:37 -0400 Subject: [PATCH 3/3] spellcheck --- Sources/mParticle-Appboy/MPKitAppboy.m | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Sources/mParticle-Appboy/MPKitAppboy.m b/Sources/mParticle-Appboy/MPKitAppboy.m index 0397bfb..5b89d70 100644 --- a/Sources/mParticle-Appboy/MPKitAppboy.m +++ b/Sources/mParticle-Appboy/MPKitAppboy.m @@ -1061,7 +1061,7 @@ - (void)updateConsent { // Update from mParticle consent if (self.configuration && self.configuration[MPConsentMappingSDKKey]) { - // Retrieve the array of Consent Map Dicitonaries from the Config + // Retrieve the array of Consent Map Dictionaries from the Config NSData *objectData = [self.configuration[MPConsentMappingSDKKey] dataUsingEncoding:NSUTF8StringEncoding]; NSArray *consentMappingArray = [NSJSONSerialization JSONObjectWithData:objectData options:NSJSONReadingMutableContainers @@ -1075,8 +1075,7 @@ - (void)updateConsent { MPGDPRConsent *consent = userConsentMap[consentPurpose.lowercaseString]; if ([brazeConsentName isEqualToString:MPGoogleAdUserDataKey]) { [appboyInstance.user setCustomAttributeWithKey:BGoogleAdUserDataKey boolValue:consent.consented]; - } - if ([brazeConsentName isEqualToString:MPGoogleAdPersonalizationKey]) { + } else if ([brazeConsentName isEqualToString:MPGoogleAdPersonalizationKey]) { [appboyInstance.user setCustomAttributeWithKey:BGoogleAdPersonalizationKey boolValue:consent.consented]; } }