Skip to content
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

Remove decide later button in explainer dialog #28

Merged
merged 2 commits into from
Apr 17, 2022
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
30 changes: 14 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# app_tracking_transparency

[![pub package](https://img.shields.io/pub/v/app_tracking_transparency.svg)](https://pub.dev/packages/app_tracking_transparency)

This Flutter plugin allows you to display ios 14+ tracking authorization dialog and request permission to collect data. Collected data is crucial for ad networks (ie admob) to work efficiently on ios 14+ devices.

## Introduction
Expand Down Expand Up @@ -40,24 +42,22 @@ final status = await AppTrackingTransparency.requestTrackingAuthorization();
// FirebaseAdMob.instance.initialize(...)
```

You can also show a custom explainer dialog before the system dialog if you want.
Google (admob) recommends implementing an explainer message that appears to users immediately before the consent dialogue. For additional info on this topic please refer to this article: https://support.google.com/admob/answer/9997589?hl=en
```dart
try {
// If the system can show an authorization request dialog
if (await AppTrackingTransparency.trackingAuthorizationStatus ==
TrackingStatus.notDetermined) {
// Show a custom explainer dialog before the system dialog
await showCustomTrackingDialog(context);
// Wait for dialog popping animation
await Future.delayed(const Duration(milliseconds: 200));
// Request system's tracking authorization dialog
await AppTrackingTransparency.requestTrackingAuthorization();
}
} on PlatformException {
// Unexpected exception was thrown
// If the system can show an authorization request dialog
if (await AppTrackingTransparency.trackingAuthorizationStatus ==
TrackingStatus.notDetermined) {
// Show a custom explainer dialog before the system dialog
await showCustomTrackingDialog(context);
// Wait for dialog popping animation
await Future.delayed(const Duration(milliseconds: 200));
// Request system's tracking authorization dialog
await AppTrackingTransparency.requestTrackingAuthorization();
}
```

The explainer dialog must not contain a "Decide later" button. It should contain only a "Continue" button and the system dialog must be shown after the explainer dialog. [See this issue for details](https://github.com/deniza/app_tracking_transparency/issues/27).

You can also get advertising identifier after authorization. Until a user grants authorization, the UUID returned will be all zeros: 00000000-0000-0000-0000-000000000000. Also note, the advertisingIdentifier will be all zeros in the Simulator, regardless of the tracking authorization status.
```dart
final uuid = await AppTrackingTransparency.getAdvertisingIdentifier();
Expand All @@ -66,8 +66,6 @@ final uuid = await AppTrackingTransparency.getAdvertisingIdentifier();
## Notes
To use this plugin you should compile your project using XCode 12 and run your app on an ios 14 device.

Google (admob) recommends implementing an explainer message that appears to users immediately before the consent dialogue. For additional info on this topic please refer to this article: <https://support.google.com/admob/answer/9997589?hl=en>

## Important Notice

IOS does not allow to display multiple native dialogs. If you try to open a native dialog when there is already a dialog on screen, previous dialog will be forcefully closed by the system. It's very common to show notification permission dialog on the first run of an ios application. If you both try to show a notification permission dialog and app tracking request dialog, one of the each will be cancelled. One way to handle this is using an explainer dialog before requesting tracking authorization. Please check the sample project for more on this. I highly recommend this approach.
Expand Down
53 changes: 27 additions & 26 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:app_tracking_transparency/app_tracking_transparency.dart';

void main() {
runApp(MaterialApp(home: HomePage()));
runApp(MyApp());
}

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage(),
);
}
}

class HomePage extends StatefulWidget {
Expand All @@ -17,38 +25,32 @@ class _HomePageState extends State<HomePage> {
@override
void initState() {
super.initState();
// Can't show a dialog in initState, delaying initialization
WidgetsBinding.instance!.addPostFrameCallback((_) => initPlugin());
initPlugin();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WidgetsBinding.instance!.addPostFrameCallback is not necessary, awaiting AppTrackingTransparency.trackingAuthorizationStatus already delays showCustomTrackingDialog.

}

// Platform messages are asynchronous, so we initialize in an async method.
Future<void> initPlugin() async {
// Platform messages may fail, so we use a try/catch PlatformException.
try {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PlatformException can not occur, because we are not using any result(FlutterError(...)) statement in platform code. System exceptions crashes the app, so flutter framework can not handle them to return PlatformException.

final TrackingStatus status =
await AppTrackingTransparency.trackingAuthorizationStatus;
setState(() => _authStatus = '$status');
// If the system can show an authorization request dialog
if (status == TrackingStatus.notDetermined) {
// Show a custom explainer dialog before the system dialog
await showCustomTrackingDialog(context);
// Wait for dialog popping animation
await Future.delayed(const Duration(milliseconds: 200));
// Request system's tracking authorization dialog
final TrackingStatus status =
await AppTrackingTransparency.trackingAuthorizationStatus;
await AppTrackingTransparency.requestTrackingAuthorization();
setState(() => _authStatus = '$status');
// If the system can show an authorization request dialog
if (status == TrackingStatus.notDetermined) {
// Show a custom explainer dialog before the system dialog
await showCustomTrackingDialog(context);
// Wait for dialog popping animation
await Future.delayed(const Duration(milliseconds: 200));
// Request system's tracking authorization dialog
final TrackingStatus status =
await AppTrackingTransparency.requestTrackingAuthorization();
setState(() => _authStatus = '$status');
}
} on PlatformException {
setState(() => _authStatus = 'PlatformException was thrown');
}

final uuid = await AppTrackingTransparency.getAdvertisingIdentifier();
print("UUID: $uuid");
}

Future<bool> showCustomTrackingDialog(BuildContext context) async =>
await showDialog<bool>(
Future<void> showCustomTrackingDialog(BuildContext context) async =>
await showDialog<void>(
context: context,
builder: (context) => AlertDialog(
title: const Text('Dear User'),
Expand All @@ -59,13 +61,12 @@ class _HomePageState extends State<HomePage> {
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context, true),
child: const Text("Continue"),
onPressed: () => Navigator.pop(context),
child: const Text('Continue'),
),
],
),
) ??
true;
);

@override
Widget build(BuildContext context) {
Expand Down
11 changes: 5 additions & 6 deletions lib/app_tracking_transparency.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,11 @@ class AppTrackingTransparency {
/// if (await AppTrackingTransparency.trackingAuthorizationStatus ==
/// TrackingStatus.notDetermined) {
/// // Show a custom explainer dialog before the system dialog
/// if (await showCustomTrackingDialog(context)) {
/// // Wait for dialog popping animation
/// await Future.delayed(const Duration(milliseconds: 200));
/// // Request system's tracking authorization dialog
/// await AppTrackingTransparency.requestTrackingAuthorization();
/// }
/// await showCustomTrackingDialog(context);
/// // Wait for dialog popping animation
/// await Future.delayed(const Duration(milliseconds: 200));
/// // Request system's tracking authorization dialog
/// await AppTrackingTransparency.requestTrackingAuthorization();
/// }
/// ```
///
Expand Down