ITMS-91053: corregir «Missing API declaration» amb Expo
Per Mehdi Azizi
Publicat el , 8 min
ITMS-91053: el teu build fa servir una API amb motiu obligatori sense declarar-la. Afegeix-ne la categoria i el codi a ios.privacyManifests i torna a fer el build.
ITMS-91053 és un control automàtic d'Apple que t'arriba per correu després de l'enviament del teu build. Diu que el codi de la teva app fa servir una API «amb motiu obligatori» (preferències, dates de fitxers, temps des de l'arrencada, espai de disc o teclats) sense explicar per què al seu manifest de privacitat. Amb Expo, la correcció es fa a ios.privacyManifests: la categoria que cita Apple, el codi que descriu el teu ús real, i després un build nou.
A Solys, el meu despertador amb minijocs, aquests motius estan declarats a la configuració de l'app. Aquí tens la seva declaració real, l'ordre que llista el que fan servir les teves dependències i la comprovació que cal fer al fitxer final abans de l'enviament.
Què vol dir l'error ITMS-91053?
El missatge es titula «ITMS-91053: Missing API declaration». Indica que el codi d'un fitxer concret del teu build fa referència a una o diverses API que exigeixen un motiu. Després llista les categories afectades, per exemple NSPrivacyAccessedAPICategoryUserDefaults.
Aquestes API no demanen cap permís a l'usuari. Però poden servir per reconèixer un dispositiu, el que Apple anomena fingerprinting. Està prohibit, fins i tot quan l'usuari accepta el seguiment. Apple ho explica a la seva pàgina sobre les API amb motiu obligatori: cada app i cada SDK ha de declarar per què les fa servir.
La mateixa pàgina fixa la regla: des de l'1 de maig de 2024, App Store Connect ja no accepta cap app que no descrigui aquests usos al seu manifest. Alguns desenvolupadors han rebut aquest correu com un simple avís, en un build acceptat. No hi comptis: tracta-ho com un bloqueig i corregeix-ho abans del pròxim enviament.
Com els altres errors ITMS, no és el rebuig d'un revisor. Ningú no ha obert la teva app: Apple ha analitzat el binari.
El privacy manifest d'iOS: el fitxer PrivacyInfo.xcprivacy
El manifest de privacitat és un fitxer anomenat PrivacyInfo.xcprivacy, situat a l'arrel del bundle de l'app. Segons la documentació d'Apple sobre els privacy manifests, descriu les dades recollides, el seguiment i les API amb motiu obligatori. Aquestes últimes van a l'array NSPrivacyAccessedAPITypes: una entrada per categoria, amb el seu tipus i la llista dels seus motius.
El punt que enganya: un manifest només cobreix el seu propi bundle. Apple ho escriu: cada executable o biblioteca dinàmica que fa servir aquestes API ha de tenir un manifest al seu bundle. El de la teva app no cobreix un framework integrat, i un SDK no pot comptar amb el de la teva app.
No el confonguis amb les frases de l'Info.plist que exigeix ITMS-90683. Aquelles es mostren a l'usuari en una sol·licitud de permís. El manifest, en canvi, només el llegeix Apple.
Les 5 categories d'API i els seus codis de motiu
El nom complet d'una categoria comença per NSPrivacyAccessedAPICategory. La llista d'API i de motius és a la pàgina de la clau NSPrivacyAccessedAPIType, consultada el 15 d'octubre de 2026.
| Categoria | API típica | Motiu habitual |
|---|---|---|
| UserDefaults | UserDefaults | CA92.1 |
| FileTimestamp | creationDate | C617.1 |
| SystemBootTime | systemUptime | 35F9.1 |
| DiskSpace | volumeAvailableCapacityKey | E174.1 |
| ActiveKeyboards | activeInputModes | 54BD.1 |
Els codis que trobaràs més sovint:
- CA92.1: l'app llegeix i escriu les seves pròpies preferències, inaccessibles per a altres apps.
- 1C8F.1: preferències compartides amb un widget o una extensió del mateix App Group.
- C617.1: dates o mida de fitxers guardats al contenidor de l'app.
- 3B52.1: fitxers que l'usuari ha triat, per exemple en un selector de documents.
- 35F9.1: mesurar el temps transcorregut entre dos esdeveniments de l'app, o fer funcionar un temporitzador.
- E174.1: comprovar l'espai lliure abans d'escriure fitxers, amb un efecte visible per a l'usuari.
- 85F4.1: mostrar l'espai de disc a l'usuari.
Declara el motiu que correspon al teu ús real, no el que sembla més ampli. Apple precisa que aquestes API i les seves dades només serveixen per als motius declarats, i mai per al seguiment. Dos codis estan reservats als SDK de tercers: C56D.1 i 0A2A.1. No tenen lloc al manifest de la teva app.
Declarar el privacy manifest a Expo
Amb Expo, no escrius el fitxer tu mateix. El descrius a expo.ios.privacyManifests, a app.json o app.config, i el prebuild genera PrivacyInfo.xcprivacy. És el mètode de la documentació d'Expo sobre els privacy manifests.
Aquí tens l'extracte real de la configuració de Solys. La clau també conté el seguiment i les dades recollides, que he tret aquí:
{
"expo": {
"ios": {
"privacyManifests": {
"NSPrivacyAccessedAPITypes": [
{
"NSPrivacyAccessedAPIType": "NSPrivacyAccessedAPICategoryUserDefaults",
"NSPrivacyAccessedAPITypeReasons": ["CA92.1", "1C8F.1"]
},
{
"NSPrivacyAccessedAPIType": "NSPrivacyAccessedAPICategoryFileTimestamp",
"NSPrivacyAccessedAPITypeReasons": ["C617.1"]
},
{
"NSPrivacyAccessedAPIType": "NSPrivacyAccessedAPICategorySystemBootTime",
"NSPrivacyAccessedAPITypeReasons": ["35F9.1"]
}
]
}
}
}
}
CA92.1, C617.1 i 35F9.1 reprenen el que declaren React Native i els mòduls Expo de l'app. 1C8F.1 ve de la mateixa Solys: l'app comparteix ajustos amb el seu widget a través d'un App Group.
Un parany que cal conèixer: si la teva carpeta ios es genera i git la ignora, un PrivacyInfo.xcprivacy escrit a mà en aquesta carpeta no arriba mai al build. EAS torna a executar el prebuild i regenera la carpeta. Ho vaig comprovar en un dels meus projectes el 9 de setembre de 2026: el manifest escrit a mà havia desaparegut després d'un prebuild. La declaració ha de viure a la configuració.
Últim punt: el manifest forma part del binari. Una actualització remota no el modifica. Cal tornar a fer un build i enviar-lo.
Els SDK de tercers que porten el seu propi manifest
La majoria de biblioteques recents inclouen el seu manifest. Els paquets Expo que fan servir aquestes API tenen un PrivacyInfo.xcprivacy a la seva carpeta ios, igual que React Native. El problema ve de la manera com s'enllacen a la teva app.
La documentació d'Expo avisa: Apple no llegeix correctament tots els manifests de les dependències CocoaPods enllaçades estàticament, que és el cas dels paquets Expo. Per tant, potser hauràs de copiar els seus motius a la configuració de la teva app.
Per reduir aquesta feina, l'opció ios.privacyManifestAggregationEnabled d'expo-build-properties fusiona els manifests de les dependències CocoaPods en un sol fitxer. Al Podfile que Expo genera als meus projectes (SDK 57), aquesta fusió està activa, tret que la desactivis.
La fusió té un límit: només veu les dependències que inclouen un manifest. Una biblioteca antiga que no en té continua sent invisible. Llegeix, doncs, el camí del fitxer que cita el correu: et diu on corregir.
| Fitxer citat | On corregir |
|---|---|
| L'executable de l'app | ios.privacyManifests |
Un .framework | Actualitzar l'SDK |
Una extensió .appex | Manifest de l'extensió |
Comprovar-ho abans de l'enviament
Expo proposa esperar el correu d'Apple després d'un enviament. Funciona, però cada anada i tornada costa un build. Aquests són els quatre controls que faig abans.
1. Llista el que declaren les teves dependències. Des de l'arrel del projecte:
find node_modules -name PrivacyInfo.xcprivacy -not -path '*/example/*' \
-exec grep -ho "NSPrivacyAccessedAPICategory[A-Za-z]*" {} + | sort | uniq -c
A Solys, el 15 d'octubre de 2026, l'ordre troba 13 manifests i quatre categories: dates de fitxers, preferències, temps des de l'arrencada i espai de disc. Cada categoria llistada ha d'aparèixer al manifest final de l'app, o al del framework que la fa servir.
2. Busca al teu propi codi natiu. Mòduls propis, plugins, targets com un widget: aquest codi, cap SDK no el declara per tu.
grep -rlE "UserDefaults|systemUptime|mach_absolute_time|creationDate|modificationDate|volumeAvailableCapacity|activeInputModes" \
--include='*.swift' --include='*.m' --include='*.mm' modules plugins targets
Adapta les carpetes al teu projecte. A Solys, és aquesta cerca la que fa aparèixer les preferències compartides per App Group, d'aquí el codi 1C8F.1.
3. Llegeix el manifest generat. Executa npx expo prebuild -p ios i després obre ios/<NomDeLaTevaApp>/PrivacyInfo.xcprivacy. Compte: aquesta ordre pot esborrar i tornar a crear la carpeta ios. Si hi has fet canvis a mà, treballa sobre una còpia del projecte.
4. Comprova el build final. És l'única prova que compta. Descarrega l'IPA des de la pàgina del build a expo.dev i executa al teu Mac:
unzip -q MyApp.ipa -d ipa
find ipa/Payload -name PrivacyInfo.xcprivacy
plutil -p ipa/Payload/*.app/PrivacyInfo.xcprivacy
La segona línia llista tots els manifests integrats, el de l'app i els dels frameworks. La tercera mostra el de l'app, per comparar-lo amb la llista del pas 1.
El que el manifest ha de dir en coherència amb la teva fitxa
El manifest no viu sol. Si declara seguiment o dades recollides, la teva fitxa de l'App Store i la teva política de privacitat han de dir el mateix. Una discrepància entre els tres pot acabar costant-te un rebuig humà, per la guideline 5.1.1. El que cal alinear està detallat a política de privacitat d'una aplicació.
Enviar el teu build sense sorpreses
Els errors ITMS es corregeixen ràpid quan saps llegir-los. Els rebuigs que vénen després demanen més perspectiva: el procediment és a la pàgina aplicació rebutjada per Apple, i els motius més freqüents són a per què Apple rebutja una app.
Per revisar el teu projecte abans de l'enviament, l'Apple Review Kit reuneix la meva checklist i skills de Claude Code que revisen el teu projecte. Si el teu enviament es bloqueja i vols una mirada humana, reserva una hora amb mi: repassem el teu projecte per videotrucada, a la teva pantalla. I si prepares el teu primer llançament, fes el teu diagnòstic gratuït: posa les etapes en ordre i t'envia la meva checklist antirebuig d'Apple.
Preguntes freqüents
ITMS-91053 bloqueja l'enviament del meu build?
Apple escriu que des de l'1 de maig de 2024, App Store Connect ja no accepta les apps que no descriuen el seu ús d'aquestes API. Tot i així, alguns desenvolupadors han rebut el correu en un build acceptat, com un avís. En tots dos casos, corregeix el manifest abans del pròxim build.
Quin codi de motiu he de triar per a UserDefaults?
CA92.1 si l'app només llegeix i escriu les seves pròpies preferències. Afegeix 1C8F.1 si les comparteix amb un widget o una extensió a través d'un App Group. C56D.1 està reservat als SDK de tercers: no el posis al manifest de la teva app.
Cal copiar el manifest de cada SDK a app.json?
No necessàriament. Si la fusió de manifests està activa, els de les dependències CocoaPods es reuneixen en instal·lar els pods. Copia una categoria només si falta al manifest final, amb el motiu que descriu l'ús real.
El meu widget o la meva extensió necessita el seu propi manifest?
Segons Apple, cada bundle que conté un executable que fa servir aquestes API ha de tenir el seu propi manifest. Una extensió és un executable a part, al seu propi bundle: el manifest de l'app no la cobreix.
Es pot corregir ITMS-91053 sense tornar a fer un build?
No. El manifest de privacitat forma part del binari. Corregeix la configuració, torna a fer un build i prova'l a TestFlight abans d'enviar-lo a revisió.