You must use the AppTrackingTransparency framework if your app collects data about end users and shares it with other companies for purposes of tracking across apps and web sites (https://developer.apple.com/documentation/apptrackingtransparency).
In this post we’ll see how implement what iOS require for the tracking and i’ll use this example also to explain other concepts.
Let’s start from the end, we want this:

Swift with Storyboard
Create a iOS project using a storyboard:




After that, we add a WebView to the storyboard and apply the constrains to have the webview in full-screen. We must add a string value for the “Privacy – Tracking Description usage” in the info tab. This message have to explain because the user is tracked.
First add an outlet for the webview:
import UIKit
import WebKit
class ViewController: UIViewController {
@IBOutlet weak var webView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
}
}
We have to add the import for the Tracking API in the SceneDelegate.swift:
import AdSupport import AppTrackingTransparency
Now add the code to show the dialog.
struct RequestManager {
static func getIDFA() -> String {
return ASIdentifierManager.shared().advertisingIdentifier.uuidString
}
static func checkTrackingStatus(completionHandler: @escaping (ATTrackingManager.AuthorizationStatus) -> Void) {
ATTrackingManager.requestTrackingAuthorization { status in
DispatchQueue.main.async {
completionHandler(status)
}
}
}
}
We create a struct RequestManager, it has two static function, the getIDFA return the Identifier For Advertisers, an UUID used to track the device.
The function checkTrackingStatus is a static function (because is defined in a struct, see https://holyswift.app/the-difference-between-class-func-and-static-func-in-swift-and-why-polymorphism-matters for long explaination) that show (in async way) the dialog to get the permission from the user.
See what’s change in the SceneDelegate:
func sceneDidBecomeActive(_ scene: UIScene) {
// Called when the scene has moved from an inactive state to an active state.
// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
attRequest()
}
func attRequest() {
RequestManager.checkTrackingStatus { status in
switch status {
case .authorized:
print("Authorized")
case .denied:
print("Denied")
case .notDetermined:
print("NotDetermined")
self.attRequest()
case .restricted:
print("Restricted")
@unknown default:
break
}
}
}
In the sceneDidBecomeActive call the our function attRequest; this function call checkTrackingStatus with a closure, this function gets the status, if the status is notDetermined, the function call itself to re-ask the authorization. Note that we get also the IDFA but in our case we don’t use it.
The code https://github.com/niqt/ShowWebsite
In SwiftUI
How have this using SwiftUI? More simple, add always the string in the plist.info to request the permission and in the code write:
import SwiftUI
import AdSupport
import AppTrackingTransparency
struct ContentView: View {
var body: some View {
VStack {
Text("Got the permission!")
}.onReceive(NotificationCenter.default.publisher(for: UIApplication.didBecomeActiveNotification)) { _ in
ATTrackingManager.requestTrackingAuthorization(completionHandler: { status in
switch status {
case .authorized:
print("A")
case .denied:
print("D")
case .notDetermined:
print("E")
case .restricted:
print(" restricted")
@unknown default:
break
}
})
}
}
}
In this case the view require the tracking authorization calling the ATTrackingManager in the onReceive of the VStack (just for example). That’s all.
Note: English is not my native language, so I’m sorry for some errors. I appreciate it if you correct me.