iTunesConnect is not allowing you to submit the app without the AppTrackingTransparency framework implementation. If you have added a tracking framework in your app you can get an error related to User Tracking Usage in iTunes Connect app privacy section.
TIP
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 websites.
The AppTrackingTransparency framework presents an app-tracking authorization request to the user and provides the tracking authorization status.
AppTrackingTransparency implementation’
For this, you don’t need a nugget package. ATTrackingManager is part of the iOS SDK (in the AppTrackingTransparency namespace), as long as you target iOS14.5 as a compilation target you will have access to it. The Xamarin.iOS bits are built-in VisualStudio, so just make sure your version is high enough.
Add NSUserTrackingUsageDescription
in info.plist
This is a message that informs the user why an app is requesting permission to use data for tracking the user or the device.
If your app calls the App Tracking Transparency API, you must provide custom text, known as a usage-description string, which displays as a system-permission alert request. The usage-description string tells the user why the app is requesting permission to use data for tracking the user or the device.
Set the NSUserTrackingUsageDescription
key in the Information Property List
(Info.plist
):
- Select your project’s
Info.plist
file in your Xamarin.iOS project. - Modify the file using the Generic PList Editor
3. Add your message with the key NSUserTrackingUsageDescription.
TIP
Use sentence-style capitalization and appropriate ending punctuation. Keep the text short and specific. You don’t need to include your app name because the system already identifies your app.
Present the app-tracking authorization request to the end user
To request user authorization to access app-related data add in your shared project:
... public interface IAppTrackingTransparencyPermission { /// <summary> /// This method checks if current status of the permission /// </summary> /// <returns></returns> Task<PermissionStatus> CheckStatusAsync(); /// <summary> /// Requests the user to accept or deny a permission /// </summary> /// <returns></returns> void RequestAsync(Action<PermissionStatus> completion); } ...
In your Xamarin.iOS project adds:
using System; using System.Collections.Generic; using System.Threading.Tasks; using Xamarin.Essentials; using XEssentialsTest.Extensions; using static Xamarin.Essentials.Permissions; namespace AppTrackingTransparency.iOS { public class AppTrackingTransparencyPermission : BasePlatformPermission, IAppTrackingTransparencyPermission { protected override Func<IEnumerable<string>> RequiredInfoPlistKeys => () => new string[] { "NSUserTrackingUsageDescription" }; // Requests the user to accept or deny a permission public void RequestAsync(Action<PermissionStatus> completion) { ATTrackingManager.RequestTrackingAuthorization((result) => completion(Convert(result))); } // This method checks if current status of the permission public override Task<PermissionStatus> CheckStatusAsync() { return Task.FromResult(Convert(ATTrackingManager.TrackingAuthorizationStatus)); } private PermissionStatus Convert(ATTrackingManagerAuthorizationStatus status) { switch (status) { case ATTrackingManagerAuthorizationStatus.NotDetermined: return PermissionStatus.Disabled; case ATTrackingManagerAuthorizationStatus.Restricted: return PermissionStatus.Restricted; case ATTrackingManagerAuthorizationStatus.Denied: return PermissionStatus.Denied; case ATTrackingManagerAuthorizationStatus.Authorized: return PermissionStatus.Granted; default: return PermissionStatus.Unknown; } } } }
... public override bool FinishedLaunching(UIApplication app, NSDictionary options) { global::Xamarin.Forms.Forms.Init(); DependencyService.Register<IAppTrackingTransparencyPermission, AppTrackingTransparencyPermission>(); LoadApplication(new App()); return base.FinishedLaunching(app, options); } ...
In order to use this implementation in your share project you can use it something like this:
... protected override async void OnStart() { if(DeviceInfo.Platform == DevicePlatform.iOS) { var appTrackingTransparencyPermission = DependencyService.Get<IAppTrackingTransparencyPermission>(); var status = await appTrackingTransparencyPermission.CheckStatusAsync(); if (status != PermissionStatus.Granted) appTrackingTransparencyPermission.RequestAsync(s => MyImplementation(s)); else MyImplementation(status); } } private void MyImplementation(PermissionStatus status) { if (status == PermissionStatus.Granted) { // app center or other implementations } } ...
Depending on why you are required to show the popup you probably don’t even need to do anything with the result.
When requesting permission is up to you, you can do it as early as possible or wait for a little until the user is engaged with the app and sees value in the tracking. Just know that while the authorization is undefined
, the permission will be zeros just as if the permission was denied
.
You can see the example source code here.