iosswiftadmobgdprconsentformapptrackingtransparency

Implement GDPR and ATT for iOS/Swift apps


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 {

            }
        }
    })
}


Solution

  • 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.