ATT bug, don't wait for user

Hello, when I'm asking for the ATT permission don't wait for the user response. I doesn't matter which approach use never waits for user answer.

Using xcode 15.2 on iOS 17.4 simulators, versions before like iOS 17.2 works without any issue.

            Task {
                self.resultStatus = await ATTrackingManager.requestTrackingAuthorization()
                completion()
            }
        }
            ATTrackingManager.requestTrackingAuthorization(completionHandler: { status in
                self.resultStatus = status
                completion()
            })
        }

This is still an issue with the iOS 17.4 RC. In addition to that, one funny thing is that once one gets a default denied status after initially calling requestTrackingAuthorizationWithCompletionHandler: method, the actual value of the authorization status is still zero (not determined). Try running this code and check the values of the callbackStatus and status:

[ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus callbackStatus) {
    ATTrackingManagerAuthorizationStatus status = [ATTrackingManager trackingAuthorizationStatus];
}];

Actually Apple test with a 17.4, we still have the problem and sometimes the ATT doesn't appear at all. So we see our app be refused when submitted. The weird fact is that we don't have the problem when building with Xcode, it's only when we deploy in TestFlight. In previous version of iOS, everything is fine.

I have the same problem. Has anyone found a solution?

Same issue here. Is there any solution? :(

This problem is impacting all apps on the store and has consequences on in-app advertising. Is there any news on the resolution?

Hi everyone, I'm writing from Italy and I have noticed the same issue. In my country the DMA is enforced, I don't know if this bug may be related to the specific implementations that have been made to comply to the DMA.

Anyway, I see the same behaviour described by @dgonzalezballester. I experimented with this bug a bit and discovered the following:

  • The same app, downloaded from the App Store, compiled with the same SDK exhibits the bug on a physical device with iOS 17.4. It behaves correctly when running my old iPhone 8 with iOS 16.7.4
  • We have code in the callback of ATT that is ran depending on the value of the status parameter being denied or accepted. I tried working around that by checking the value of ATTrackingManager.trackingAuthorizationStatus to no avail, because the callback doesn't get called again when the user actually makes the choice
  • To demonstrate the point, I tried running a while loop in a background thread inside the callback that stops when the value of ATTrackingManager.trackingAuthorizationStatus changes from .notDetermined. In the body of the while I ran the code depending on ATTrackingManager.trackingAuthorizationStatus and not the status parameter passed in the callback. This actually worked, but is a very dirty workaround that I'm not willing to put it in a build production.

I am getting this problem on real devices too after updating them to iOS 17.4.

I can see the correct status in the device settings yet the call back always returns .denied without waiting for the user choice.

Unfortunately iOS 17.4.1 has come out, and the issue still persists.

Hi everyone,

As you know, due to a bug in iOS 17.4, ATTrackingManager.requestTrackingAuthorization() immediately triggers the callback with a value of status = denied, even though the true value of ATTrackingManager.trackingAuthorizationStatus is still notDetermined because the user has not yet made a choice by responding to the tracking consent popup. The issue persists on iOS 17.4.1.

Anyway, the app triggers a didBecomeActiveNotification when the user responds to the popup, so we can use this workaround to avoid the issue and proceed only after the user has made a choice:

func requestTrackingAuthorization() {
    self.removeObserver()
    
    ATTrackingManager.requestTrackingAuthorization {
        [weak self] status in
        
        if status == .denied,
           ATTrackingManager.trackingAuthorizationStatus == .notDetermined {
            debugPrint("iOS 17.4 authorization bug detected")
            self?.addObserver()
            return
        }
        
        debugPrint("status = \(status)")
    }
}

private weak var observer: NSObjectProtocol?

private func addObserver() {
    self.removeObserver()
    self.observer = NotificationCenter.default.addObserver(
        forName: UIApplication.didBecomeActiveNotification,
        object: nil,
        queue: .main
    ) { [weak self] _ in
        self?.requestTrackingAuthorization()
    }
}

private func removeObserver() {
    if let observer {
        NotificationCenter.default.removeObserver(observer)
    }
    self.observer = nil
}

@davidebalistreri nice one, thanks for sharing.

In the past couple days I also opened a ticket on the Feeback Assistant tool and as of today the bug has been recognized with, I quote, a potential fix identified for a future OS update.

Same error. Tested on lots of devices (17.4 + 17.4.1).

Same issue here. This is a very horrible bug to have. Do we even know if 17.4.2 is fixing this? Seems like the only fix for now is to block all those in iOS 17.4 from seeing the ATT alert. :(

It looks like this is fixed in the first iOS 17.5 beta.

I am seeing the alert presented correctly without calling the completion closure immediately with denied. The closure is now only called once you interact with the buttons on the alert.

I have tested this out on a number of different iOS versions and I can confirm @donnywdavis's observation that this is resolved in the iOS 17.5 beta.

Here are the results of my testing:

 --------------------------------------
 | iOS     | Works? | Bug? | Test      |
 --------------------------------------
 | 16.4.0  | Yes    | No   | Simulator |
 | 17.0.0  | Yes    | No   | Simulator |
 | 17.2.0  | Yes    | No   | Simulator |
 | 17.3.1  | Yes    | No   | Device    |
 | 17.4.0  | Yes    | Yes  | Simulator |
 | 17.4.1  | Yes    | Yes  | Simulator |
 | 17.5.0b | Yes    | No   | Device    |
 --------------------------------------

Even though Apple is providing a fix, this bug will always be out there and will be relevant for quite a while. So, I have adapted the solution from @davidebalistreri into a drop in replacement for ATTrackingManager.requestTrackingAuthorization().

final class BugFixingATTrackingRequestManager {
    class func requestTrackingAuthorization() async -> ATTrackingManager.AuthorizationStatus {
        let status = await ATTrackingManager.requestTrackingAuthorization()
        if status == .denied, ATTrackingManager.trackingAuthorizationStatus == .notDetermined {
            debugPrint("iOS 17.4 ATT bug detected")
            for await _ in await NotificationCenter.default.notifications(named: UIApplication.didBecomeActiveNotification) {
                return await requestTrackingAuthorization()
            }
        }

        return status
    }
}

This solution improves on the above by being more compact, supporting async/await, and returning the AuthorizationStatus which allows it to be used directly as a replacement for let status = await ATTrackingManager.requestTrackingAuthorization()

Hope this is helpful.

Where do i put this? I'm new to app development

I can confirm this bug happens on tvOS 17.4. I have an iOS running on 16.3, which doesn't have the bug.

If anyone would like an example requesting app tracking authorization using the workaround from @davidfromgainesville, but in the form of Objective-C, here is the code I used that is working for me:

void requestTrackingAuthorization()
{
    [ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
        if (status == ATTrackingManagerAuthorizationStatusDenied && [ATTrackingManager trackingAuthorizationStatus] == ATTrackingManagerAuthorizationStatusNotDetermined)
        {
            [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidBecomeActiveNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
                requestTrackingAuthorization();
            }];
        }
        else
        {
            // Do something with status
        }
    }];
}

iOS 17.5 is now live and the bug seems to fixed.

The issue persists on iOS 17.5 on actual devices.

This issue is so strange to me. We released the app tracking transparency last week. It worked fine when I ran the debug app with an Apple TV device on 17.4. Then I tried the one from the AppStore, but it didn't work. And I can't turn on the allow tracking from the setting.

I updated my device to 17.5, which briefly allowed me to turn on the tracking; when I ran the same app from the AppStore, I didn't get the app tracking transparency dialog, and when I rechecked the settings, I couldn't turn on the allow tracking option.

Is anyone experiencing the same issue?

I'm also getting spammed with main thread warnings when I call

    func sceneDidBecomeActive(_ scene: UIScene) {
        Task { [weak self] in
            guard let self else { return }
            
            await ATTrackingManager.requestTrackingAuthorization()
        }
    }

{"message":"This code path does I/O on the main thread underneath that can lead to UI responsiveness issues. Consider ways to optimize this code path","antipattern trigger":"-[NSData dataWithContentsOfFile:options:error:]","message type":"suppressable","show in console":"0"}

ATT bug, don't wait for user
 
 
Q