ITMS-91053: oprava „Missing API declaration“ v Expo
Autor: Mehdi Azizi
Publikováno , 8 min
ITMS-91053: tvůj build používá API s povinným důvodem a nedeklaruje ho. Přidej kategorii a kód do ios.privacyManifests a udělej nový build.
ITMS-91053 je automatická kontrola Applu, kterou dostaneš e-mailem po odeslání buildu. Říká, že kód tvé appky používá API „s povinným důvodem“ (preference, data souborů, čas od spuštění systému, místo na disku nebo klávesnice) a v manifestu soukromí nevysvětluje proč. V Expo se to opravuje v ios.privacyManifests: kategorie, kterou Apple uvádí, kód popisující tvé skutečné použití a pak nový build.
V Solys, mém budíku s minihrami, jsou tyhle důvody deklarované v konfiguraci appky. Ukážu ti její skutečnou deklaraci, příkaz, který vypíše, co používají tvoje závislosti, a kontrolu výsledného souboru před odesláním.
Co znamená chyba ITMS-91053?
Zpráva má název „ITMS-91053: Missing API declaration“. Říká, že kód v konkrétním souboru tvého buildu odkazuje na jedno nebo víc API, která vyžadují důvod. Pak vypíše dotčené kategorie, třeba NSPrivacyAccessedAPICategoryUserDefaults.
Tahle API po uživateli nechtějí žádné oprávnění. Dají se ale použít k rozpoznání zařízení, čemuž Apple říká fingerprinting. To je zakázané, i když uživatel se sledováním souhlasí. Apple to vysvětluje na stránce o API s povinným důvodem: každá appka a každé SDK musí deklarovat, proč je používá.
Stejná stránka stanovuje pravidlo: od 1. května 2024 App Store Connect nepřijme appku, která tato použití nepopisuje ve svém manifestu. Někteří vývojáři hlásili tenhle e-mail jen jako varování u přijatého buildu. Nespoléhej na to: ber to jako blokaci a oprav to před dalším odesláním.
Stejně jako ostatní chyby ITMS to není zamítnutí od revieweru. Nikdo tvou appku neotevřel: Apple analyzoval binárku.
Privacy manifest v iOS: soubor PrivacyInfo.xcprivacy
Manifest soukromí je soubor PrivacyInfo.xcprivacy v kořeni bundlu appky. Podle dokumentace Applu k privacy manifestům popisuje sbíraná data, sledování a API s povinným důvodem. Ta patří do pole NSPrivacyAccessedAPITypes: jedna položka na kategorii, s typem a seznamem důvodů.
Tady je past: manifest pokrývá jen svůj vlastní bundle. Apple to píše přímo: každý spustitelný soubor nebo dynamická knihovna, která tato API používá, musí mít manifest ve svém bundlu. Manifest tvé appky nepokrývá vložený framework a SDK se nemůže spoléhat na manifest tvé appky.
Nepleť si ho s texty v Info.plist, které vyžaduje ITMS-90683. Ty se uživateli zobrazí v žádosti o oprávnění. Manifest čte jen Apple.
5 kategorií API a jejich kódy důvodů
Celý název kategorie začíná NSPrivacyAccessedAPICategory. Seznam API a důvodů najdeš na stránce klíče NSPrivacyAccessedAPIType, přečteno 15. října 2026.
| Kategorie | Typické API | Běžný důvod |
|---|---|---|
| UserDefaults | UserDefaults | CA92.1 |
| FileTimestamp | creationDate | C617.1 |
| SystemBootTime | systemUptime | 35F9.1 |
| DiskSpace | volumeAvailableCapacityKey | E174.1 |
| ActiveKeyboards | activeInputModes | 54BD.1 |
Kódy, na které narazíš nejčastěji:
- CA92.1: appka čte a zapisuje své vlastní preference, nedostupné jiným appkám.
- 1C8F.1: preference sdílené s widgetem nebo rozšířením ve stejné App Group.
- C617.1: data nebo velikost souborů uložených v kontejneru appky.
- 3B52.1: soubory, které vybral uživatel, třeba v dialogu pro výběr dokumentů.
- 35F9.1: měření času mezi dvěma událostmi v appce nebo běh časovače.
- E174.1: kontrola volného místa před zápisem souborů, s viditelným dopadem pro uživatele.
- 85F4.1: zobrazení místa na disku uživateli.
Deklaruj důvod, který odpovídá tvému skutečnému použití, ne ten, co vypadá nejširší. Apple upřesňuje, že tato API a jejich data slouží jen k deklarovaným důvodům a nikdy ke sledování. Dva kódy jsou vyhrazené pro SDK třetích stran: C56D.1 a 0A2A.1. V manifestu tvé appky nemají co dělat.
Deklarace privacy manifestu v Expo
V Expo ten soubor nepíšeš sám. Popíšeš ho pod expo.ios.privacyManifests v app.json nebo app.config a prebuild vygeneruje PrivacyInfo.xcprivacy. To je postup z dokumentace Expo k privacy manifestům.
Tady je skutečný výřez z konfigurace Solys. Klíč obsahuje i sledování a sbíraná data, ta jsem tu vynechal:
{
"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 a 35F9.1 přebírají to, co deklaruje React Native a moduly Expo v appce. 1C8F.1 pochází přímo ze Solys: appka sdílí nastavení se svým widgetem přes App Group.
Past, o které je dobré vědět: pokud je tvoje složka ios generovaná a ignorovaná gitem, ručně napsaný PrivacyInfo.xcprivacy v téhle složce se do buildu nikdy nedostane. EAS znovu spustí prebuild a složku přegeneruje. Ověřil jsem si to na jednom svém projektu 9. září 2026: ručně napsaný manifest po prebuildu zmizel. Deklarace musí žít v konfiguraci.
Poslední věc: manifest je součástí binárky. Vzdálená aktualizace ho nezmění. Musíš udělat nový build a znovu ho odeslat.
SDK třetích stran s vlastním manifestem
Většina novějších knihoven svůj manifest dodává. Balíčky Expo, které tato API používají, mají PrivacyInfo.xcprivacy ve své složce ios, stejně jako React Native. Problém je v tom, jak jsou k tvé appce připojené.
Dokumentace Expo varuje: Apple nečte správně všechny manifesty závislostí CocoaPods linkovaných staticky, což je případ balíčků Expo. Může se tedy stát, že jejich důvody budeš muset zkopírovat do konfigurace své appky.
Aby té práce bylo méně, nastavení ios.privacyManifestAggregationEnabled z expo-build-properties slučuje manifesty závislostí CocoaPods do jednoho souboru. V Podfilu, který Expo generuje na mých projektech (SDK 57), je toto slučování zapnuté, pokud ho nevypneš.
Slučování má jeden limit: vidí jen závislosti, které manifest dodávají. Starší knihovna bez manifestu zůstane neviditelná. Přečti si proto cestu k souboru uvedenou v e-mailu: říká ti, kde opravovat.
| Uvedený soubor | Kde opravit |
|---|---|
| Spustitelný soubor appky | ios.privacyManifests |
.framework | Aktualizovat SDK |
Rozšíření .appex | Manifest rozšíření |
Kontrola před odesláním
Expo navrhuje po odeslání počkat na e-mail od Applu. Funguje to, ale každé kolečko stojí jeden build. Tady jsou čtyři kontroly, které dělám předem.
1. Vypiš, co deklarují tvoje závislosti. Z kořene projektu:
find node_modules -name PrivacyInfo.xcprivacy -not -path '*/example/*' \
-exec grep -ho "NSPrivacyAccessedAPICategory[A-Za-z]*" {} + | sort | uniq -c
U Solys příkaz 15. října 2026 našel 13 manifestů a čtyři kategorie: data souborů, preference, čas od spuštění systému a místo na disku. Každá vypsaná kategorie se musí objevit ve výsledném manifestu appky, nebo v manifestu frameworku, který ji používá.
2. Prohledej svůj vlastní nativní kód. Vlastní moduly, pluginy, targety jako widget: tenhle kód za tebe žádné SDK nedeklaruje.
grep -rlE "UserDefaults|systemUptime|mach_absolute_time|creationDate|modificationDate|volumeAvailableCapacity|activeInputModes" \
--include='*.swift' --include='*.m' --include='*.mm' modules plugins targets
Složky si uprav podle svého projektu. U Solys právě tohle hledání odhalí preference sdílené přes App Group, odtud kód 1C8F.1.
3. Přečti si vygenerovaný manifest. Spusť npx expo prebuild -p ios a otevři ios/<NazevTveAppky>/PrivacyInfo.xcprivacy. Pozor: tenhle příkaz může složku ios smazat a vytvořit znovu. Pokud v ní máš ruční úpravy, pracuj na kopii projektu.
4. Zkontroluj výsledný build. To je jediný důkaz, který se počítá. Stáhni IPA ze stránky buildu na expo.dev a na Macu spusť:
unzip -q MojeAppka.ipa -d ipa
find ipa/Payload -name PrivacyInfo.xcprivacy
plutil -p ipa/Payload/*.app/PrivacyInfo.xcprivacy
Druhý řádek vypíše všechny vložené manifesty, appky i frameworků. Třetí zobrazí manifest appky, který porovnáš se seznamem z kroku 1.
Co musí manifest říkat ve shodě s tvou stránkou v App Storu
Manifest nežije sám. Pokud deklaruje sledování nebo sbíraná data, tvoje stránka v App Storu a zásady ochrany osobních údajů musí říkat totéž. Nesoulad mezi těmi třemi tě pak může stát lidské zamítnutí podle guideline 5.1.1. Co je potřeba sladit, najdeš v článku zásady ochrany osobních údajů aplikace.
Odešli build bez nepříjemných překvapení
Chyby ITMS se opravují rychle, když je umíš číst. Zamítnutí, která přijdou potom, chtějí víc nadhledu: postup je na stránce aplikace zamítnutá Applem a nejčastější důvody najdeš v článku proč Apple zamítá appky.
Pro kontrolu před odesláním obsahuje Apple Review Kit můj checklist a skills pro Claude Code, které projdou tvůj projekt. Pokud se ti odeslání zaseklo a chceš lidský pohled, zarezervuj si se mnou hodinu: projdeme tvůj projekt přes videohovor, na tvé obrazovce. A pokud chystáš své první vydání, udělej si bezplatnou diagnostiku: seřadí ti kroky a pošle ti můj checklist proti zamítnutí od Applu.
Časté dotazy
Blokuje ITMS-91053 odeslání mého buildu?
Apple píše, že od 1. května 2024 App Store Connect nepřijímá appky, které nepopisují použití těchto API. Někteří vývojáři ale e-mail dostali u přijatého buildu jako varování. V obou případech oprav manifest před dalším buildem.
Jaký kód důvodu zvolit pro UserDefaults?
CA92.1, pokud appka čte a zapisuje jen své vlastní preference. Přidej 1C8F.1, pokud je sdílí s widgetem nebo rozšířením přes App Group. C56D.1 je vyhrazený pro SDK třetích stran: do manifestu své appky ho nedávej.
Musím do app.json kopírovat manifest každého SDK?
Ne nutně. Pokud je slučování manifestů zapnuté, manifesty závislostí CocoaPods se spojí při instalaci podů. Kategorii zkopíruj jen tehdy, když ve výsledném manifestu chybí, a to s důvodem, který popisuje skutečné použití.
Potřebuje můj widget nebo rozšíření vlastní manifest?
Podle Applu musí mít každý bundle se spustitelným souborem, který tato API používá, vlastní manifest. Rozšíření je samostatný spustitelný soubor ve vlastním bundlu: manifest appky ho nepokrývá.
Dá se ITMS-91053 opravit bez nového buildu?
Ne. Manifest soukromí je součástí binárky. Oprav konfiguraci, udělej nový build a pak ho otestuj v TestFlight, než ho pošleš do review.