Skip to content

feat(analytics): add consent mode v2 #12298

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
Mar 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@
<string>arm64</string>
</array>
<key>MinimumOSVersion</key>
<string>11.0</string>
<string>12.0</string>
</dict>
</plist>
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Loading