Implement GDPR and ATT for iOS/Swift apps

1.9k views Asked by At

My app was rejected by Apple for showing GDPR (Google's UMP) and ATT confusing users. Specifically, if the user is in the EEA, GDPR will show up first. Only then did ATT start showing up. As per Apple's request: "If the user denies permission to track once, do not ask them to allow tracking again within the same permission request flow. There should be no tracking activity until the user grants permission to track". So I need to know the result of the user filling out the GDPR form so that I can decide whether to show ATT or not.

And I still don't have a solution.

This is my Code

func setupAdvertisement() {
    fatalError("This method must be overridden in the subclass")
}

func requestATTAuthorization() {
    if #available(iOS 14.5, *) {
        let trackingAuthorizationStatus = ATTrackingManager.trackingAuthorizationStatus
        if trackingAuthorizationStatus == .notDetermined {
            ATTrackingManager.requestTrackingAuthorization(completionHandler: { status in

            })
        }
    }
}

func showAdvertisement() {
    if #available(iOS 14.5, *) {
        let trackingAuthorizationStatus = ATTrackingManager.trackingAuthorizationStatus
        if trackingAuthorizationStatus == .notDetermined {
            ATTrackingManager.requestTrackingAuthorization(completionHandler: { [weak self] status in
                DispatchQueue.main.async {
                    self?.setupAdvertisement()
                }
            })
        } else {
            DispatchQueue.main.async {
                self.setupAdvertisement()
            }
        }
    } else {
        DispatchQueue.main.async {
            self.setupAdvertisement()
        }
    }
}

@objc func showAdBasedOnConsentStatus() {
    let consentStatus = UMPConsentInformation.sharedInstance.consentStatus

    switch consentStatus {
    case UMPConsentStatus.required:
        loadForm()
    case UMPConsentStatus.obtained:
        showAdvertisement()
    case UMPConsentStatus.notRequired:
        showAdvertisement()
    case UMPConsentStatus.unknown:
        print("Error showAdBasedOnConsentStatus()")
    @unknown default:
        print("Error showAdBasedOnConsentStatus()")
    }
}

func UMPSetup() {
    let parameters = UMPRequestParameters()
    parameters.tagForUnderAgeOfConsent = false


    UMPConsentInformation.sharedInstance.requestConsentInfoUpdate(
        with: parameters,
        completionHandler: { [weak self] error in
            if let error = error {

                print(error)
            } else {
                let formStatus = UMPConsentInformation.sharedInstance.formStatus
                if formStatus == UMPFormStatus.available {
                    self?.loadForm()
                } else {
                    self?.requestATTAuthorization()
                }
            }
        })
}

func loadForm() {
    UMPConsentForm.load(completionHandler: { form, loadError in
        if loadError != nil {

        } else {
            if UMPConsentInformation.sharedInstance.consentStatus == UMPConsentStatus.required {
                form?.present(from: self, completionHandler: { dismissError in
                    if UMPConsentInformation.sharedInstance.consentStatus == UMPConsentStatus.obtained {
                        self.showAdBasedOnConsentStatus()
                    }
                    self.loadForm()
                })
            } else {

            }
        }
    })
}

2

There are 2 answers

4
oneshot On BEST ANSWER

First of all, you should let UMP deal with the IDFA message, in addition to the GDPR consent form. So that you don't need to present the IDFA message in your code also. Here is explained how to implement it, it's very simple and do not require code, you just need to edit your plist file, link the ATT framework and create the IDFA message on your AdMob profile. I can't really test it to check right now, but I'd assume Google is smart enough to have figured your issue out for you since it's an Apple requirement.

If this is not the case however, there is a great solution by another user that lets you know the user GDPR preferences once set. I tested this recently and it still works. Since it is about the IDFA, I guess you should look at the canShowPersonalizedAds() method.

0
peetadelic On

Our company had similar reason of rejection.

We do not use UMP for IDFA, just for GDPR.

But I think the general idea about the implementation, if you do not use Google's UMP:

  1. Show IDFA prompt manually from code (that Apple's native UIAlert with Allow tracking or Ask App Not to Track)
  2. Upon dismissal of IDFA prompt, present GDPR consent. But only for EU/EEU/UK users, if not EU/EEU/UK user, proceed to next step.
  3. Initialise AdMob SDK.

The targeted ads and privacy madness is somehow solved by the magic in the AdMob SDK.

Since we are on Apple platform, I would go for IDFA first and then GDPR.

⬇️ Here is also proposed "next step" from Apple's rejection email/message: ⬇️

If the user denies permission to track once, do not ask them to allow tracking again within the same permission request flow. There should be no tracking activity until the user grants permission to track.

If you collect data after the user selects "Ask App Not to Track" on the App Tracking Transparency permission request, please revise the GDPR prompt and clarify that you collect data but do not track.

If your app shows the GDPR prompt before showing the App Tracking Transparency permission request, there is no need to modify the wording of the GDPR prompt.