From 2f971517f1b6c7f25d0f489539c765510e1931d9 Mon Sep 17 00:00:00 2001 From: Brandon Stalnaker <33703490+BrandonStalnaker@users.noreply.github.com> Date: Mon, 9 Sep 2024 11:04:27 -0400 Subject: [PATCH] feat: Implement Google EU Consent (#94) * feat: Implement Google EU Consent * update logic * spellcheck --- Sources/mParticle-Appboy/MPKitAppboy.m | 46 ++++++++++++++++++++++++++ mParticle-Appboy.podspec | 10 +++--- 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/Sources/mParticle-Appboy/MPKitAppboy.m b/Sources/mParticle-Appboy/MPKitAppboy.m index 18bf6db..5b89d70 100644 --- a/Sources/mParticle-Appboy/MPKitAppboy.m +++ b/Sources/mParticle-Appboy/MPKitAppboy.m @@ -47,6 +47,15 @@ static NSString *const promotionKey = @"promotions"; 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"; +static NSString *const BGoogleAdPersonalizationKey = @"$google_ad_personalization"; + #if TARGET_OS_IOS static id inAppMessageControllerDelegate = nil; static BOOL shouldDisableNotificationHandling = NO; @@ -325,6 +334,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 +1049,40 @@ - (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 && self.configuration[MPConsentMappingSDKKey]) { + // Retrieve the array of Consent Map Dictionaries 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]; + } else if ([brazeConsentName isEqualToString: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