Skip to content

Commit

Permalink
feat(analytics): add consent mode v2 (#12298)
Browse files Browse the repository at this point in the history
Co-authored-by: matin-zadeh-dolatabad <matin.zadeh.dolatabad@schibsted.com>
Co-authored-by: Guillaume Bernos <guillaume.bernos@gmail.com>
Co-authored-by: Guillaume Bernos <guillaume@bernos.dev>
  • Loading branch information
4 people committed Mar 20, 2024
1 parent 85a9b18 commit 19f3dbd
Show file tree
Hide file tree
Showing 14 changed files with 254 additions and 26 deletions.
Expand Up @@ -9,6 +9,9 @@
public class Constants {
public static final String AD_STORAGE_CONSENT_GRANTED = "adStorageConsentGranted";
public static final String ANALYTICS_STORAGE_CONSENT_GRANTED = "analyticsStorageConsentGranted";
public static final String AD_PERSONALIZATION_SIGNALS_CONSENT_GRANTED =
"adPersonalizationSignalsConsentGranted";
public static final String AD_USER_DATA_CONSENT_GRANTED = "adUserDataConsentGranted";
public static final String USER_ID = "userId";
public static final String EVENT_NAME = "eventName";
public static final String PARAMETERS = "parameters";
Expand Down
Expand Up @@ -291,6 +291,10 @@ private Task<Void> setConsent(final Map<String, Object> arguments) {
(Boolean) arguments.get(Constants.AD_STORAGE_CONSENT_GRANTED);
final Boolean analyticsStorageGranted =
(Boolean) arguments.get(Constants.ANALYTICS_STORAGE_CONSENT_GRANTED);
final Boolean adPersonalizationSignalsGranted =
(Boolean) arguments.get(Constants.AD_PERSONALIZATION_SIGNALS_CONSENT_GRANTED);
final Boolean adUserDataGranted =
(Boolean) arguments.get(Constants.AD_USER_DATA_CONSENT_GRANTED);
HashMap<FirebaseAnalytics.ConsentType, FirebaseAnalytics.ConsentStatus> parameters =
new HashMap<>();

Expand All @@ -310,6 +314,22 @@ private Task<Void> setConsent(final Map<String, Object> arguments) {
: FirebaseAnalytics.ConsentStatus.DENIED);
}

if (adPersonalizationSignalsGranted != null) {
parameters.put(
FirebaseAnalytics.ConsentType.AD_PERSONALIZATION,
adPersonalizationSignalsGranted
? FirebaseAnalytics.ConsentStatus.GRANTED
: FirebaseAnalytics.ConsentStatus.DENIED);
}

if (adUserDataGranted != null) {
parameters.put(
FirebaseAnalytics.ConsentType.AD_USER_DATA,
adUserDataGranted
? FirebaseAnalytics.ConsentStatus.GRANTED
: FirebaseAnalytics.ConsentStatus.DENIED);
}

analytics.setConsent(parameters);
taskCompletionSource.setResult(null);
} catch (Exception e) {
Expand Down
Expand Up @@ -25,6 +25,6 @@
<string>arm64</string>
</array>
<key>MinimumOSVersion</key>
<string>11.0</string>
<string>12.0</string>
</dict>
</plist>
@@ -1,5 +1,5 @@
# Uncomment this line to define a global platform for your project
platform :ios, '11.0'
platform :ios, '12.0'

# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
Expand Down
Expand Up @@ -130,7 +130,11 @@ class _MyHomePageState extends State<MyHomePage> {
}

Future<void> _testSetConsent() async {
await widget.analytics.setConsent(adStorageConsentGranted: true);
await widget.analytics.setConsent(
adStorageConsentGranted: true,
adUserDataConsentGranted: true,
adPersonalizationSignalsConsentGranted: true,
);
setMessage('setConsent succeeded');
}

Expand Down
Expand Up @@ -15,6 +15,9 @@
NSString *const kFLTFirebaseAnalyticsParameters = @"parameters";
NSString *const kFLTFirebaseAnalyticsAdStorageConsentGranted = @"adStorageConsentGranted";
NSString *const kFLTFirebaseAnalyticsStorageConsentGranted = @"analyticsStorageConsentGranted";
NSString *const kFLTFirebaseAdPersonalizationSignalsConsentGranted =
@"adPersonalizationSignalsConsentGranted";
NSString *const kFLTFirebaseAdUserDataConsentGranted = @"adUserDataConsentGranted";
NSString *const kFLTFirebaseAnalyticsUserId = @"userId";

NSString *const FLTFirebaseAnalyticsChannelName = @"plugins.flutter.io/firebase_analytics";
Expand Down Expand Up @@ -137,6 +140,10 @@ - (void)resetAnalyticsDataWithMethodCallResult:(FLTFirebaseMethodCallResult *)re
- (void)setConsent:(id)arguments withMethodCallResult:(FLTFirebaseMethodCallResult *)result {
NSNumber *adStorageGranted = arguments[kFLTFirebaseAnalyticsAdStorageConsentGranted];
NSNumber *analyticsStorageGranted = arguments[kFLTFirebaseAnalyticsStorageConsentGranted];
NSNumber *adPersonalizationSignalsGranted =
arguments[kFLTFirebaseAdPersonalizationSignalsConsentGranted];
NSNumber *adUserDataGranted = arguments[kFLTFirebaseAdUserDataConsentGranted];

NSMutableDictionary<FIRConsentType, FIRConsentStatus> *parameters =
[[NSMutableDictionary alloc] init];

Expand All @@ -149,6 +156,17 @@ - (void)setConsent:(id)arguments withMethodCallResult:(FLTFirebaseMethodCallResu
[analyticsStorageGranted boolValue] ? FIRConsentStatusGranted : FIRConsentStatusDenied;
}

if (adPersonalizationSignalsGranted != nil) {
parameters[FIRConsentTypeAdPersonalization] = [adPersonalizationSignalsGranted boolValue]
? FIRConsentStatusGranted
: FIRConsentStatusDenied;
}

if (adUserDataGranted != nil) {
parameters[FIRConsentTypeAdUserData] =
[adUserDataGranted boolValue] ? FIRConsentStatusGranted : FIRConsentStatusDenied;
}

[FIRAnalytics setConsent:parameters];
result.success(nil);
}
Expand Down
Expand Up @@ -125,14 +125,44 @@ class FirebaseAnalytics extends FirebasePluginPlatform {
);
}

/// Sets the applicable end user consent state. 'default' value for 'adStorageConsentGranted' & 'analyticsStorageConsentGranted' is 'true'
/// Sets the applicable end user consent state.
/// By default, no consent mode values are set.
///
/// - [adStorageConsentGranted] - Enables storage, such as cookies, related to advertising. (Platform: Android, iOS, Web)
/// - [analyticsStorageConsentGranted] - Enables storage, such as cookies, related to analytics (for example, visit duration). (Platform: Android, iOS, Web)
/// - [adPersonalizationSignalsConsentGranted] - Sets consent for personalized advertising. (Platform: Android, iOS, Web)
/// - [adUserDataConsentGranted] - Sets consent for sending user data to Google for advertising purposes. (Platform: Android, iOS, Web)
/// - [functionalityStorageConsentGranted] - Enables storage that supports the functionality of the website or app such as language settings. (Platform: Web)
/// - [personalizationStorageConsentGranted] - Enables storage related to personalization such as video recommendations. (Platform: Web)
/// - [securityStorageConsentGranted] - Enables storage related to security such as authentication functionality, fraud prevention, and other user protection. (Platform: Web)
///
/// Default consents can be set according to the platform:
/// - [iOS][1]
/// - [Android][2]
/// - [Web][3]
///
/// [1]: https://developers.google.com/tag-platform/security/guides/app-consent?platform=ios#default-consent
/// [2]: https://developers.google.com/tag-platform/security/guides/app-consent?platform=android#default-consent
/// [3]: https://firebase.google.com/docs/reference/js/analytics.md#setconsent_1697027
Future<void> setConsent({
bool? adStorageConsentGranted,
bool? analyticsStorageConsentGranted,
bool? adPersonalizationSignalsConsentGranted,
bool? adUserDataConsentGranted,
bool? functionalityStorageConsentGranted,
bool? personalizationStorageConsentGranted,
bool? securityStorageConsentGranted,
}) async {
await _delegate.setConsent(
adStorageConsentGranted: adStorageConsentGranted,
analyticsStorageConsentGranted: analyticsStorageConsentGranted,
adPersonalizationSignalsConsentGranted:
adPersonalizationSignalsConsentGranted,
adUserDataConsentGranted: adUserDataConsentGranted,
functionalityStorageConsentGranted: functionalityStorageConsentGranted,
personalizationStorageConsentGranted:
personalizationStorageConsentGranted,
securityStorageConsentGranted: securityStorageConsentGranted,
);
}

Expand Down
Expand Up @@ -73,6 +73,11 @@ class MethodChannelFirebaseAnalytics extends FirebaseAnalyticsPlatform {
Future<void> setConsent({
bool? adStorageConsentGranted,
bool? analyticsStorageConsentGranted,
bool? adPersonalizationSignalsConsentGranted,
bool? adUserDataConsentGranted,
bool? functionalityStorageConsentGranted,
bool? personalizationStorageConsentGranted,
bool? securityStorageConsentGranted,
}) async {
try {
return channel.invokeMethod<void>(
Expand All @@ -82,6 +87,11 @@ class MethodChannelFirebaseAnalytics extends FirebaseAnalyticsPlatform {
'adStorageConsentGranted': adStorageConsentGranted,
if (analyticsStorageConsentGranted != null)
'analyticsStorageConsentGranted': analyticsStorageConsentGranted,
if (adPersonalizationSignalsConsentGranted != null)
'adPersonalizationSignalsConsentGranted':
adPersonalizationSignalsConsentGranted,
if (adUserDataConsentGranted != null)
'adUserDataConsentGranted': adUserDataConsentGranted,
},
);
} catch (e, s) {
Expand Down
Expand Up @@ -167,9 +167,32 @@ abstract class FirebaseAnalyticsPlatform extends PlatformInterface {
}

/// Sets the applicable end user consent state.
/// By default, no consent mode values are set.
///
/// - [adStorageConsentGranted] - Enables storage, such as cookies, related to advertising. (Platform: Android, iOS, Web)
/// - [analyticsStorageConsentGranted] - Enables storage, such as cookies, related to analytics (for example, visit duration). (Platform: Android, iOS, Web)
/// - [adPersonalizationSignalsConsentGranted] - Sets consent for personalized advertising. (Platform: Android, iOS, Web)
/// - [adUserDataConsentGranted] - Sets consent for sending user data to Google for advertising purposes. (Platform: Android, iOS, Web)
/// - [functionalityStorageConsentGranted] - Enables storage that supports the functionality of the website or app such as language settings. (Platform: Web)
/// - [personalizationStorageConsentGranted] - Enables storage related to personalization such as video recommendations. (Platform: Web)
/// - [securityStorageConsentGranted] - Enables storage related to security such as authentication functionality, fraud prevention, and other user protection. (Platform: Web)
///
/// Default consents can be set according to the platform:
/// - [iOS][1]
/// - [Android][2]
/// - [Web][3]
///
/// [1]: https://developers.google.com/tag-platform/security/guides/app-consent?platform=ios#default-consent
/// [2]: https://developers.google.com/tag-platform/security/guides/app-consent?platform=android#default-consent
/// [3]: https://firebase.google.com/docs/reference/js/analytics.md#setconsent_1697027
Future<void> setConsent({
bool? adStorageConsentGranted,
bool? analyticsStorageConsentGranted,
bool? adPersonalizationSignalsConsentGranted,
bool? adUserDataConsentGranted,
bool? functionalityStorageConsentGranted,
bool? personalizationStorageConsentGranted,
bool? securityStorageConsentGranted,
}) {
throw UnimplementedError('setConsent() is not implemented');
}
Expand Down
Expand Up @@ -67,8 +67,25 @@ class FirebaseAnalyticsWeb extends FirebaseAnalyticsPlatform {
Future<void> setConsent({
bool? adStorageConsentGranted,
bool? analyticsStorageConsentGranted,
bool? adPersonalizationSignalsConsentGranted,
bool? adUserDataConsentGranted,
bool? functionalityStorageConsentGranted,
bool? personalizationStorageConsentGranted,
bool? securityStorageConsentGranted,
}) async {
throw UnimplementedError('setConsent() is not supported on Web.');
return convertWebExceptions(() {
return _delegate.setConsent(
adStorageConsentGranted: adStorageConsentGranted,
analyticsStorageConsentGranted: analyticsStorageConsentGranted,
adPersonalizationSignalsConsentGranted:
adPersonalizationSignalsConsentGranted,
adUserDataConsentGranted: adUserDataConsentGranted,
functionalityStorageConsentGranted: functionalityStorageConsentGranted,
personalizationStorageConsentGranted:
personalizationStorageConsentGranted,
securityStorageConsentGranted: securityStorageConsentGranted,
);
});
}

@override
Expand Down
Expand Up @@ -53,6 +53,42 @@ class Analytics extends JsObjectWrapper<analytics_interop.AnalyticsJsImpl> {
);
}

void setConsent({
bool? adPersonalizationSignalsConsentGranted,
bool? adStorageConsentGranted,
bool? adUserDataConsentGranted,
bool? analyticsStorageConsentGranted,
bool? functionalityStorageConsentGranted,
bool? personalizationStorageConsentGranted,
bool? securityStorageConsentGranted,
}) {
final consentSettings = {
if (adPersonalizationSignalsConsentGranted != null)
'ad_personalization':
adPersonalizationSignalsConsentGranted ? 'granted' : 'denied',
if (adStorageConsentGranted != null)
'ad_storage': adStorageConsentGranted ? 'granted' : 'denied',
if (adUserDataConsentGranted != null)
'ad_user_data': adUserDataConsentGranted ? 'granted' : 'denied',
if (analyticsStorageConsentGranted != null)
'analytics_storage':
analyticsStorageConsentGranted ? 'granted' : 'denied',
if (functionalityStorageConsentGranted != null)
'functionality_storage':
functionalityStorageConsentGranted ? 'granted' : 'denied',
if (personalizationStorageConsentGranted != null)
'personalization_storage':
personalizationStorageConsentGranted ? 'granted' : 'denied',
if (securityStorageConsentGranted != null)
'security_storage':
securityStorageConsentGranted ? 'granted' : 'denied',
}.jsify();

return analytics_interop.setConsent(
consentSettings,
);
}

void setAnalyticsCollectionEnabled({required bool enabled}) {
return analytics_interop.setAnalyticsCollectionEnabled(
jsObject,
Expand Down
Expand Up @@ -32,6 +32,13 @@ external void logEvent(
JSObject? callOptions,
);

@JS()
@staticInterop
external void setConsent(
// https://firebase.google.com/docs/reference/js/analytics.consentsettings.md#consentsettings_interface
JSAny? consentSettings,
);

@JS()
@staticInterop
external void setAnalyticsCollectionEnabled(
Expand Down

0 comments on commit 19f3dbd

Please sign in to comment.