iosflutterpush-notificationapptrackingtransparency

How to request tracking transparency permission before Notification permission in flutter iOS


Each time I run my App, the Notification dialog comes way before the App tracking authorization. I'd like the user to see at first the App tracking Transparency dialog before the Notification dialog. I tried requesting the tracking authorization await AppTrackingTransparency.requestTrackingAuthorization(); before the runApp() or after it and above the Push Notification request await PushNotificationService().setupInteractedMessage(); and added the key in info.plist, however, the result is the same, notification dialog comes first. Kindly check my code.

int? initScreen;

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // await Firebase.initializeApp();
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );
  // runApp(MyApp());
  SharedPreferences preferences = await SharedPreferences.getInstance();
  initScreen = await preferences.getInt('initScreen');
  await preferences.setInt('initScreen', 1);
  // MobileAds.instance.initialize();
  runApp(MyApp());
  //await AppTracking
  // final status = await AppTrackingTransparency.requestTrackingAuthorization();
  await AppTrackingTransparency.requestTrackingAuthorization();
  await PushNotificationService().setupInteractedMessage();
  MobileAds.instance.initialize();
  RemoteMessage? initialMessage =
      await FirebaseMessaging.instance.getInitialMessage();
  if (initialMessage != null) {
    // App received a notification when it was killed
  }
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  // final TrackingStatus status;
  //
  // MyApp({required this.status});

  static FirebaseAnalytics analytics = FirebaseAnalytics.instance;
  static FirebaseAnalyticsObserver observer =
      new FirebaseAnalyticsObserver(analytics: analytics);

  @override
  Widget build(BuildContext context) {
    // String statusText;

    // switch (status) {
    //   case TrackingStatus.authorized:
    //     statusText = 'Tracking Status Authorized';
    //     break;
    //   case TrackingStatus.denied:
    //     statusText = 'Tracking Status Denied';
    //     break;
    //   case TrackingStatus.notDetermined:
    //     statusText = 'Tracking Status Not Determined';
    //     break;
    //   case TrackingStatus.notSupported:
    //     statusText = 'Tracking Status Not Supported';
    //     break;
    //   case TrackingStatus.restricted:
    //     statusText = 'Tracking Status Restricted';
    //     break;
    //   default:
    //     statusText = 'You should not see this...';
    //     break;
    // }

    return GetMaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Culture Islamique',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      // home:

      initialRoute: initScreen == 0 || initScreen == null ? 'onboard' : 'home',
      routes: {
        'home': (context) => navbar(analytics: analytics, observer: observer),
        'onboard': (context) => onboardingHomePage(),
      },
    );
  }
}```

[![enter image description here][1]][1]


  [1]: https://i.sstatic.net/R3eHd.png

Solution

  • IOS does not allow to display multiple native dialogs.

    Here is my workaround inspired by the example provided by the app-tracking-transparency package on pub.dev

    First, I removed the await AppTrackingTransparency.requestTrackingAuthorization(); from main instead call it in the HomeScreen (navbar).

    Next, in the HomeScreen call this function initPlugin() in initState() see the code.

    class navbar extends StatefulWidget {
      const navbar({
        Key? key,
        required this.analytics,
        required this.observer,
      }) : super(key: key);
    
      final FirebaseAnalytics analytics;
      final FirebaseAnalyticsObserver observer;
    
      @override
      _navbarState createState() => _navbarState();
    }
    
    class _navbarState extends State<navbar> {
      String _authStatus = 'Unknown';
      int currentindex = 0;
    
    
      // Platform messages are asynchronous, so we initialize in an async method.
      Future<void> initPlugin() async {
        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.requestTrackingAuthorization();
          setState(() => _authStatus = '$status');
        }
    
        // final uuid = await AppTrackingTransparency.getAdvertisingIdentifier();
        final uuid = await AppTrackingTransparency.getAdvertisingIdentifier();
        print("UUID: $uuid");
      }
    
      Future<void> showCustomTrackingDialog(BuildContext context) async =>
          await showDialog<void>(
            context: context,
            builder: (context) => AlertDialog(
              title: const Text('Dear User'),
              content: const Text(
                "We care about your privacy and data security. We keep this app free by showing ads. Can we continue to use your data to tailor ads for you?\n\nYou can change your choice anytime in the app settings. Our partners will collect data and use a unique identifier on your device to show you ads.",
              ),
              actions: [
                TextButton(
                  onPressed: () => Navigator.pop(context),
                  style: TextButton.styleFrom(
                      backgroundColor: color.AppColor.homePageDetail),
                  child: const Text(
                    'Continue',
                    style: TextStyle(color: Colors.white),
                  ),
                ),
              ],
            ),
          );
    
      @override
      void initState() {
        super.initState();
    // It is safer to call native code using addPostFrameCallback after the widget has been fully built and initialized.
        // Directly calling native code from initState may result in errors due to the widget tree not being fully built at that point. 
        WidgetsFlutterBinding.ensureInitialized()
            .addPostFrameCallback((_) => initPlugin());
        print("Tracking status: $_authStatus\n");
      }
    
      List ListOfColors = [
        HomeScreen(),
        All(),
        ProfileScreen(),
      ];
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: ListOfColors[currentindex],
          bottomNavigationBar: BottomNavyBar(
            selectedIndex: currentindex,
            onItemSelected: (index) {
              setState(
                () {
                  interstitialAd?.show();
                  currentindex = index;
                  print("$_authStatus");
                },
              );
            },
            items: [
              BottomNavyBarItem(
                  icon: Icon(Icons.question_answer),
                  title: Text("Quiz"),
                  activeColor: Color(0xFF6985e8),
                  inactiveColor: Color(0xffa2a2b1)),
              BottomNavyBarItem(
                  icon: Icon(Icons.book),
                  title: Text("Histoires "),
                  activeColor: Color(0xFF6985e8),
                  inactiveColor: Color(0xffa2a2b1)),
              BottomNavyBarItem(
                  icon: Icon(Icons.settings),
                  title: Text("Paramètres"),
                  activeColor: Color(0xFF6985e8),
                  inactiveColor: Color(0xffa2a2b1)),
            ],
          ),
        );
      }
    }
    
    

    After that, Once you run your App, the notification permission will come first, followed by the explanatory dialog then the app tracking authorization permission will be requested. This will prevent your app from being rejected from the App Store.

    For more info check the [example][1]

    [1]: https://pub.dev/packages/app_tracking_transparency/example on pub.dev