deniza / app_tracking_transparency

A Flutter plugin to show ios 14+ tracking authorization dialog.
https://pub.dev/packages/app_tracking_transparency/
MIT License
83 stars 28 forks source link

Authorisation popup is not showing in iOS 16.5 #44

Open amitaman opened 1 year ago

amitaman commented 1 year ago

Hi Team, i am using the latest version of ATT in my flutter app when i published my app to app store they rejected saying: We're looking forward to completing our review, but we need more information to continue. Your app uses the AppTrackingTransparency framework, but we are unable to locate the App Tracking Transparency permission request when reviewed on iOS 16.5.

Method: Future<void> initPlugin() async { // Platform messages may fail, so we use a try/catch PlatformException. try { final TrackingStatus status = await AppTrackingTransparency.trackingAuthorizationStatus; setState(() => _authStatus = '$status'); // If the system can show an authorization request dialog if (status == TrackingStatus.notDetermined) { final TrackingStatus status = await AppTrackingTransparency.requestTrackingAuthorization(); setState(() => _authStatus = '$status'); if (status == TrackingStatus.authorized && defaultTargetPlatform == TargetPlatform.iOS) { _webViewController!.evaluateJavascript( source: 'document.getElementById("onetrust-accept-btn-handler").click()', ); } } } on PlatformException { setState(() => _authStatus = 'PlatformException was thrown'); } final uuid = await AppTrackingTransparency.getAdvertisingIdentifier(); if (kDebugMode) { print("UUID: $uuid"); }

Calling: void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) => initPlugin()); }

mkbsugita commented 1 year ago

Can you write in formatted text with three back quote?

Did you try it? https://github.com/deniza/app_tracking_transparency/issues/32

    TrackingStatus authorizationStatus =
        await AppTrackingTransparency.trackingAuthorizationStatus;
    int timeoutCount = 0;
    while (authorizationStatus == TrackingStatus.notDetermined &&
        timeoutCount < 10) { // Adjust yourself.. maybe up to ~50
      authorizationStatus =
          await AppTrackingTransparency.requestTrackingAuthorization();
      await Future.delayed(const Duration(milliseconds: 200));
      timeoutCount++;
    }
luminkhant commented 1 year ago

I have the same issue today. Apple reject since it is not working for iOS 16.5, Did you already find out the solution ? @amitaman

Zaveri21 commented 1 year ago

@luminkhant i was facing this same issue. I added bellow code in appDelegate.swift file and Authorisation default alert showing in iOS 16+

func applicationDidBecomeActive(_ application: UIApplication) {
    if #available(iOS 14, *) {
        ATTrackingManager.requestTrackingAuthorization { status in
            switch status {
            case .authorized:
                // Tracking authorization dialog was shown
                // and we are authorized
                print("Authorized")
            case .denied:
                // Tracking authorization dialog was
                // shown and permission is denied
                print("Denied")
            case .notDetermined:
                // Tracking authorization dialog has not been shown
                print("Not Determined")
            case .restricted:
                print("Restricted")
            @unknown default:
                print("Unknown")
            }
        }
    }
}
deniza commented 1 year ago

hi @Zaveri21

The code you provided is printing current tracking status. Could you please explain what else you did to make it work in your case? Thank you.

JariHuomo commented 1 year ago

I would like to hear more details too @Zaveri21 how you got this fixed, thanks!

Zaveri21 commented 1 year ago

Hi @deniza & @JariHuomo Happy coding 😀

My app was approved and live in apple store with the help of above code block.

this swift code will work for iOS 14 or above version. ATTrackingManager.requestTrackingAuthorization used for ask permission so that default iOS permission alert will open. so I added this code in my applicationDidBecomeActive method so on app launch/active I am able to prompt alert until package app_tracking_transparency issue resolved. I used this package flutter side to handle App tracking transparency for lower version nothing changed in dart side code.

deniza commented 1 year ago

Thanks for the explanation. I want to present further information and recommend a more flutter friendly approach:

The applicationDidBecomeActive function in iOS is called when your app is brought to the foreground. This can happen when the user taps on your app icon, or the app moved from inactive to active state.

Showing a native dialog in iOS will result in the application switching to the inactive state. This is because the dialog will take focus away from your app, and the system will need to pause your app's execution until the dialog is dismissed.

You can not display ATT dialog when the application is in inactive state. I suspect that your application somehow become inactive during the call to requestTrackingAuthorization function and hence does not work properly. The most common reason for this to happen is that you request some other permission like notification permission, or camera usage permission that also shows a native dialog and sends your app to inactive state.

You can always check that your application is in an active state before calling requestTrackingAuthorization function. In your stateful widget, override didChangeAppLifecycleState function like this:

class _MyWidgetState extends State<MyApp> {
...
@override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    if (state == AppLifecycleState.resumed) {
      // App has been brought to the foreground.
      // call ATT functionality here. ie: ATTrackingManager.requestTrackingAuthorization
    }
  }

Below approach is better than calling ATT in a delayed Future call, or in a loop as suggested by other fellow developers. Also you stay in the dart side instead of native code, which may be more preferable.

Please try it if you have any issues and respond this thread if it's working or not working in your use case.

amitaman commented 1 year ago

I have the same issue today. Apple reject since it is not working for iOS 16.5, Did you already find out the solution ? @amitaman

Hi @luminkhant My app is also got approved. i used an extra dialog, before showing the actual Authorization dialog.


    // Platform messages may fail, so we use a try/catch PlatformException.
    try {
      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
        if (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');
        }
        if (status == TrackingStatus.authorized && defaultTargetPlatform == TargetPlatform.iOS) {
         //
        }
      }
    } on PlatformException {
      setState(() => _authStatus = 'PlatformException was thrown');
    }
    final uuid = await AppTrackingTransparency.getAdvertisingIdentifier();
    if (kDebugMode) {
      print("UUID: $uuid");
    }
  }```

```Future<bool> showCustomTrackingDialog(BuildContext context) async =>
    await showDialog<bool>(
      context: context,
      builder: (context) => AlertDialog(
        title: const Text('Dear User'),
        content: const Text(
          Constants.attMessage,
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context, true),
            child: const Text('Continue'),
          ),
        ],
      ),
    ) ??
    false;```
onurkagan commented 1 year ago

The problem seems on Apple. They rejected my app update with the same reason. But when i installed ios 16.5 on an iPhone and work it, I saw that permission was requested. Somehow i think there is a problem during the review. I sent the screen recording of the application and explained that the request came to the screen as soon as the application was opened and this time they approved it. I think there is no problem with the package.

yanqiuLove commented 11 months ago

我的项目是Flutter创建的,iOS端语言使用的是OC,针对该问题我的解决方案如下: 在AppDelegate.m文件中加入以下代码:

import <AppTrackingTransparency/AppTrackingTransparency.h>

import <AdSupport/ASIdentifierManager.h>

- (void)applicationDidBecomeActive:(UIApplication *)application { if (@available(iOS 14, *)) { // iOS14及以上版本先请求权限 [ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) { // 获取到权限后使用老方法获取idfa if (status == ATTrackingManagerAuthorizationStatusAuthorized) { NSString *idfa = [[ASIdentifierManager sharedManager].advertisingIdentifier UUIDString]; NSLog(@"%@",idfa); } else { NSLog(@"请在设置-隐私-跟踪中允许App请求跟踪"); } }]; } else { // iOS14以下版本使用老方法 // 判断在设置-隐私里是否打开了广告跟踪 if ([[ASIdentifierManager sharedManager] isAdvertisingTrackingEnabled]) { NSString *idfa = [[ASIdentifierManager sharedManager].advertisingIdentifier UUIDString]; NSLog(@"%@",idfa); } else { NSLog(@"请在设置-隐私-广告中打开广告跟踪功能"); } } }

michaelsof47 commented 11 months ago

where i have to access package from app_tracking_transparency ?

SancoDevs1 commented 10 months ago

HI all, i am facing this issue on IOS 16.6, unable to see the ATT prompt on ios 16.6 whereas it is coming in previous versions. any solution for it, please guide, thanks,

michaelsof47 commented 10 months ago

is there package that i have modified ? i want to try it to modify support iOS 16.6

SahidKhan89 commented 10 months ago

Has anyone found a workaround for this package to work with iOS 16.6 ?

Apple keep rejecting now.

deniza commented 10 months ago

Hi. I tested the package both on ios 16.5 and 16.6 and it seems working fine for me. Please try to call it delayed in a Future.delayed callback, or use an explainer dialog before showing native ATT dialog.

edismooth commented 10 months ago

Same issue. Now I changed this plugin to permission_handler. I hope they will approve it. Btw if you want to crate fix for this plugin you can compare this two files (I know, the second one is not Swift):

https://github.com/deniza/app_tracking_transparency/blob/master/ios/Classes/SwiftAppTrackingTransparencyPlugin.swift

https://github.com/Baseflow/flutter-permission-handler/blob/main/permission_handler_apple/ios/Classes/strategies/AppTrackingTransparencyPermissionStrategy.m

deniza commented 10 months ago

This plugin, or any of the att plugins out there do nothing fancy actually. We just check and return ATT status with one function call; ATTrackingManager.trackingAuthorizationStatus, and show ATT dialog by using another api call; ATTrackingManager.requestTrackingAuthorization.

Other then some cosmetic differences both of the implementations are the same; just a basic wrapper around native functionality.

edismooth commented 10 months ago

Thank you for your quick reply @deniza!

I missed that example with description: https://github.com/deniza/app_tracking_transparency/blob/a072384e2299ad3021aab2ca5e6031a7bf40079e/example/lib/main.dart#L31C3-L31C89 I hope that now the application will pass Apple's review without any problems.

Mik77o commented 9 months ago

Today , we got from app reviewer... SmartSelect_20230922_173932_Gmail.jpg

mzm008 commented 6 months ago

I think the request dialog is not reopen when user reject this auth

timokz commented 6 months ago

Hey @deniza thanks for your work and the active contributions. What is your suggested approach of resolving this issue occuring? calling the ATT dialog in didChangeAppLifecycleState , or something like awaiting a delayed future? EDIT: Assuming your example code is already in use, calling the dialog after initialization is comple.

G4SD3O commented 5 months ago

Hi there

I encounter the similar problem. App rejected by Apple "We're looking forward to completing our review, but we need more information to continue. Your app uses the AppTrackingTransparency framework, but we are unable to locate the App Tracking Transparency permission request when reviewed on iOS 17.3." As I am using XCode 15.2, I can't test with a simulator with an iOS version higher than 17.2 (Thanks Apple for not providing the right tools to test without a real device).

Anyway, here is the code I use

My main widget is a ConsumerStatefulWidget (from riverpod)

InitState method

@override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) {
      _requestAppTracking();
    });
  } 

_requestAppTracking method

  Future<void> _requestAppTracking() async {
    Future<void>.delayed(timeout).then((value) async {
      final TrackingStatus status =
          await AppTrackingTransparency.trackingAuthorizationStatus;
      developer.log('Tracking Status Init: $status');
      // If the system can show an authorization request dialog
      if (status == TrackingStatus.notDetermined) {
        // Request system's tracking authorization dialog
        final TrackingStatus status =
            await AppTrackingTransparency.requestTrackingAuthorization();
        developer.log('Tracking Status After Request: $status');
      }

      ref.read(splashStateProvider.notifier).updateState(SplashState.initGame);
    });
  }

build method

@override
  Widget build(BuildContext context) {
    ref.listen<SplashState>(splashStateProvider,
        (SplashState? previousState, SplashState newState) async {
      switch (newState) {
        case SplashState.ready:
          Navigator.pushNamed(
            context,
            "/home",
          );
          break;
        case SplashState.initGame:
          await _initApp();
          break;
        case SplashState.requestAppTransparency:
          break;
      }
    });
...

_initApp method

Future<void> _initApp() async {
    //bunch of services initialization. Not relevant here

    ref.read(splashStateProvider.notifier).updateState(SplashState.ready);
  }

I finally could get my hands on a device with 17.3 installed and indeed the AppTrackingPopup does not show during the startup. What is even weirder is that the app navigates to the "home" screen (as stated in the listen section in build()). This only happens if the await AppTrackingTransparency.requestTrackingAuthorization() directly returns without waiting for action from the user.

I am a bit lost here. Anyone with similar issue with 17.3 ? Thanks for your help

RyosukeOK commented 5 months ago

@G4SD3O I have the same issue today. Apple reject my app since it is not working for iOS 17.3 .

Guideline 2.1 - Information Needed We're looking forward to completing our review, but we need more information to continue. Your app uses the AppTrackingTransparency framework, but we are unable to locate the App Tracking Transparency permission request when reviewed on iOS 17.3. ~~

G4SD3O commented 5 months ago

It works on the simulator with iOS 17.2 and the release note for iOS 17.3 does not indicate major change in this area so this is very weird. @deniza any thoughts? ;)

deniza commented 5 months ago

To expedite the troubleshooting process, I'd like to suggest testing the plugin with a simplified test code. This is often helpful in isolating potential conflicts or integration issues within your larger app's codebase. Can you please test the plugin in such a test environment?

G4SD3O commented 5 months ago

I have created a simple project to reproduce the issue. Here are my first results:

  1. it works perfectly using a simulator with iOS 17.2
  2. I have been testing on a real phone with iOS 17.3 but this one belongs to my daughter who is less than 18 years old so the tracking is automatically disabled (status = TrackingStatus.restricted). That is why the ATT popup never appears. Good to know for future tests

I still need to find a real phone with iOS 17.3 as the latest Xcode version does not allow me to test this version.

Does anyone know an online service (free or very cheap) we can use to do further testing?