App Tracking Transparency con Combine
Come incapsulare ATTrackingManager e ASIdentifierManager in un ObservableObject con Combine, per chiedere il consenso al tracking e leggere l'advertising ID.
Tradotto dall’inglese con l’aiuto dell’IA e rivisto dall’autore.Leggi l’originale

Una delle funzionalità più pubblicizzate di iOS 14.5 è la nuova App Tracking Transparency. In giro ci sono moltissimi articoli che cercano di chiarire le posizioni in gioco in questa decisione di Apple e delle controparti come Facebook. Non voglio addentrarmi nell'aspetto politico della questione. Vorrei invece fare una rapida panoramica di ciò che serve per lavorare con questa novità e di cosa significa dal punto di vista tecnologico.
App Tracking Transparency si basa su un solo componente software, una classe chiamata ATTrackingManager.
class ATTrackingManager : NSObjectSecondo Apple questa classe offre tutto il necessario per chiedere il permesso e ottenere lo stato attuale della richiesta. Collabora con l'Ad framework per identificare gli utenti in forma anonima e consentire di tracciarne abitudini e interessi.

L'Ad framework ha un'istanza condivisa, disponibile in tutto il sistema, sotto forma di una classe chiamata ASIdentifierManager. Possiamo ottenerla nel modo classico:
ASIdentifierManager.shared()Inoltre possiamo leggere l'identificatore anonimo corrente in modo altrettanto semplice:
ASIdentifierManager.shared().advertisingIdentifierPrima di iOS 14.5 voi (sviluppatori) avevate sempre la possibilità di ottenere questo identificatore sotto forma di oggetto UUID. L'identificatore è anonimo e coerente in tutto il sistema operativo, e permette di tracciare gli utenti tra app e domini diversi. Questo, ovviamente, può compromettere la privacy se uno o più attori in gioco hanno cattive intenzioni (e, credetemi, di attori malintenzionati ce ne sono tantissimi in giro).

Da iOS 14.5 bisogna chiedere il consenso dell'utente, app per app, prima di poter accedere a questo identificatore. Significa che voi (utenti) potete decidere in ogni momento chi può accedere al vostro identificatore, sia all'installazione dell'app sia, se cambiate idea, dalle Impostazioni. Dal punto di vista dei diritti dell'utente è fantastico, e non è nemmeno discutibile.

Il nostro obiettivo di oggi è incapsulare queste classi in un oggetto più comodo, da usare sia con Swift sia con SwiftUI. Per riuscirci useremo alcune funzionalità di base di Combine, in modo da esporre correttamente tutti i pezzi che ci servono.
Per brevità useremo un approccio SwiftUI puro, ma tutto il codice sarà pronto anche per i progetti Swift standard. Cominciamo creando un progetto SwiftUI.
La prima cosa da fare è aggiungere la descrizione nel nostro Info.plist, in modo da popolare correttamente il messaggio che vedranno gli utenti. Come con CoreLocation o Photos, dobbiamo descrivere con una frase efficace cosa ci serve e perché chiediamo il consenso al tracking. Per farlo aggiungiamo una nuova chiave NSUserTrackingUsageDescription e la relativa stringa.

Quando siamo pronti, possiamo scrivere la classe helper che esporrà alla nostra app gli accessor necessari. L'abbiamo chiamata ATTrackingHelper. Poiché vogliamo essere notificati a ogni cambiamento di AuthorizationStatus o di AdvertisingIdentifier, ereditiamo da ObservableObject e marchiamo le due proprietà interessate con @Published. Questo significa che Combine, dietro le quinte, genererà per noi tutto il codice necessario per tracciare i cambiamenti e notificare i subscriber.

L'ultimo pezzo che manca per rendere utile questa classe è un metodo requestAuth(), che interagirà con il framework e popolerà di conseguenza i risultati.
class ATTrackingHelper: ObservableObject {
@Published var status = ATTrackingManager.trackingAuthorizationStatus
@Published var currentUUID = ASIdentifierManager.shared().advertisingIdentifier
func requestAuth() {
guard ATTrackingManager.trackingAuthorizationStatus != .authorized else {
return
}
ATTrackingManager.requestTrackingAuthorization { status in
DispatchQueue.main.async { [unowned self] in
self.status = status
if status == .authorized {
self.currentUUID = ASIdentifierManager.shared().advertisingIdentifier
}
}
}
}
}È il momento di un Proof-Of-Concept. Con questo approccio basta dichiarare un ObservedObject nella nostra ContentView. Più o meno così:
struct ContentView: View {
@ObservedObject var trackingHelper = ATTrackingHelper()
var body: some View {
VStack(alignment: .leading){
Text("Your advertising ID:").font(.callout)
Text("\(trackingHelper.currentUUID.uuidString)").font(.caption)
HStack {
Spacer()
Button(action: {
trackingHelper.requestAuth()
}, label: {
Text("Ask for tracking")
})
Spacer()
}.padding(.vertical)
}
.padding()
}
}Ora possiamo chiedere il consenso all'utente, la prima volta che eseguiamo l'app, e popolare la uuidString richiesta. Che bel periodo per essere sviluppatori iOS! :-)
Happy coding! 🖖🏻
