From 9f97e449cefbac00f395a0be6e1d49bc1ee6375a Mon Sep 17 00:00:00 2001 From: BrandonStalnaker Date: Thu, 28 Mar 2024 12:34:51 -0400 Subject: [PATCH] feat: Support Google Consent --- ...icle-Google-Analytics-Firebase-GA4.podspec | 4 +- .../MPKitFirebaseGA4Analytics.m | 61 +++++++++++++++++++ 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/mParticle-Google-Analytics-Firebase-GA4.podspec b/mParticle-Google-Analytics-Firebase-GA4.podspec index e99bc7e..0a5509e 100755 --- a/mParticle-Google-Analytics-Firebase-GA4.podspec +++ b/mParticle-Google-Analytics-Firebase-GA4.podspec @@ -19,13 +19,13 @@ Pod::Spec.new do |s| s.ios.dependency 'mParticle-Apple-SDK/mParticle', '~> 8.0' s.ios.frameworks = 'CoreTelephony', 'SystemConfiguration' s.libraries = 'z' - s.ios.dependency 'Firebase/Core', '~> 10.6' + s.ios.dependency 'Firebase/Core', '~> 10.23' s.tvos.deployment_target = "12.0" s.tvos.source_files = 'mParticle-Google-Analytics-Firebase-GA4/*.{h,m,mm}' s.tvos.dependency 'mParticle-Apple-SDK/mParticle', '~> 8.0' s.tvos.frameworks = 'SystemConfiguration' s.libraries = 'z' - s.tvos.dependency 'Firebase/Core', '~> 10.6' + s.tvos.dependency 'Firebase/Core', '~> 10.23' end diff --git a/mParticle-Google-Analytics-Firebase-GA4/MPKitFirebaseGA4Analytics.m b/mParticle-Google-Analytics-Firebase-GA4/MPKitFirebaseGA4Analytics.m index ce4d02b..ef6847b 100755 --- a/mParticle-Google-Analytics-Firebase-GA4/MPKitFirebaseGA4Analytics.m +++ b/mParticle-Google-Analytics-Firebase-GA4/MPKitFirebaseGA4Analytics.m @@ -5,9 +5,11 @@ #if __has_include() #import #import + #import #else #import "FirebaseCore/FirebaseCore.h" #import "FirebaseAnalytics/FIRAnalytics.h" + #import "FirebaseAnalytics/FIRAnalytics+Consent.h" #endif #endif @@ -42,6 +44,15 @@ @implementation MPKitFirebaseGA4Analytics static NSString *const instanceIdIntegrationKey = @"app_instance_id"; static NSString *const invalidFirebaseKey = @"invalid_ga4_key"; +static NSString *const kMPFIRGA4AdStorageKey = @"ad_storage"; +static NSString *const kMPFIRGA4AdUserDataKey = @"ad_user_data"; +static NSString *const kMPFIRGA4AdPersonalizationKey = @"ad_personalization"; +static NSString *const kMPFIRGA4AnalyticsStorageKey = @"analytics_storage"; +static NSString *const kMPFIRGA4DefaultAdStorageKey = @"defaultAdStorageConsentSDK"; +static NSString *const kMPFIRGA4DefaultAdUserDataKey = @"defaultAdUserDataConsentSDK"; +static NSString *const kMPFIRGA4DefaultAdPersonalizationKey = @"defaultAdPersonalizationConsentSDK"; +static NSString *const kMPFIRGA4DefaultAnalyticsStorageKey = @"defaultAnalyticsStorageConsentSDK"; + // Following limits are based off Google Analytics 360 limits, docs here "https://support.google.com/analytics/answer/11202874?sjid=14644072134282618832-NA#limits" const NSInteger FIR_MAX_CHARACTERS_EVENT_NAME = 40; const NSInteger FIR_MAX_CHARACTERS_IDENTITY_NAME = 24; @@ -87,6 +98,8 @@ - (MPKitExecStatus *)didFinishLaunchingWithConfiguration:(NSDictionary *)configu [self updateInstanceIDIntegration]; + [self updateConsent]; + _started = YES; dispatch_async(dispatch_get_main_queue(), ^{ @@ -358,6 +371,54 @@ - (void)logUserAttributes:(NSDictionary *)userAttributes { } } +- (MPKitExecStatus *)setConsentState:(nullable MPConsentState *)state { + [self updateConsent]; + + return [self execStatus:MPKitReturnCodeSuccess]; +} + +- (void)updateConsent { + // If Defaults are not set do not send FIRAnalytics Consent + if (!self.configuration[kMPFIRGA4DefaultAdStorageKey] ) { + return; + } + + // Default Consent States + FIRConsentStatus adStorageStatus = [self.configuration[kMPFIRGA4DefaultAdStorageKey] isEqual: @"Granted"] ? FIRConsentStatusGranted : FIRConsentStatusDenied; + FIRConsentStatus adUserDataStatus = [self.configuration[kMPFIRGA4DefaultAdUserDataKey] isEqual: @"Granted"] ? FIRConsentStatusGranted : FIRConsentStatusDenied; + FIRConsentStatus analyticsStorageStatus = [self.configuration[kMPFIRGA4DefaultAnalyticsStorageKey] isEqual: @"Granted"] ? FIRConsentStatusGranted : FIRConsentStatusDenied; + FIRConsentStatus adPersonalizationStatus = [self.configuration[kMPFIRGA4DefaultAdPersonalizationKey] isEqual: @"Granted"] ? FIRConsentStatusGranted : FIRConsentStatusDenied; + + MParticleUser *currentUser = [[[MParticle sharedInstance] identity] currentUser]; + NSDictionary *userConsentMap = currentUser.consentState.gdprConsentState; + + // Update from mParticle Consent + if (self.configuration[kMPFIRGA4AdStorageKey] && userConsentMap[self.configuration[kMPFIRGA4AdStorageKey]]) { + MPGDPRConsent *consent = userConsentMap[self.configuration[kMPFIRGA4AdStorageKey]]; + adStorageStatus = consent.consented ? FIRConsentStatusGranted : FIRConsentStatusDenied; + } + if (self.configuration[kMPFIRGA4AdUserDataKey] && userConsentMap[self.configuration[kMPFIRGA4AdUserDataKey]]) { + MPGDPRConsent *consent = userConsentMap[self.configuration[kMPFIRGA4AdUserDataKey]]; + adUserDataStatus = consent.consented ? FIRConsentStatusGranted : FIRConsentStatusDenied; + } + if (self.configuration[kMPFIRGA4AnalyticsStorageKey] && userConsentMap[self.configuration[kMPFIRGA4AnalyticsStorageKey]]) { + MPGDPRConsent *consent = userConsentMap[self.configuration[kMPFIRGA4AnalyticsStorageKey]]; + analyticsStorageStatus = consent.consented ? FIRConsentStatusGranted : FIRConsentStatusDenied; + } + if (self.configuration[kMPFIRGA4AdPersonalizationKey] && userConsentMap[self.configuration[kMPFIRGA4AdPersonalizationKey]]) { + MPGDPRConsent *consent = userConsentMap[self.configuration[kMPFIRGA4AdPersonalizationKey]]; + adPersonalizationStatus = consent.consented ? FIRConsentStatusGranted : FIRConsentStatusDenied; + } + + // Update Consent State with FIRAnalytics + [FIRAnalytics setConsent:@{ + FIRConsentTypeAnalyticsStorage : analyticsStorageStatus, + FIRConsentTypeAdStorage : adStorageStatus, + FIRConsentTypeAdUserData : adUserDataStatus, + FIRConsentTypeAdPersonalization : adPersonalizationStatus, + }]; +} + - (NSString *)getEventNameForCommerceEvent:(MPCommerceEvent *)commerceEvent parameters:(NSDictionary *)parameters { switch (commerceEvent.action) { case MPCommerceEventActionAddToCart: