ITMS-90338: oprava „Non-public API usage“ v Expo
Autor: Mehdi Azizi
Zverejnené , 9 min
ITMS-90338: tvoj build obsahuje metódu, funkciu alebo triedu, ktorú Apple považuje za súkromnú. Nájdi príslušnú závislosť, aktualizuj ju a sprav nový build.
ITMS-90338 je automatická kontrola tvojho buildu zo strany Apple. Hovorí, že tvoj binárny súbor odkazuje na API, ktoré Apple považuje za súkromné: metódy Objective-C, funkcie alebo triedy. Oprava: nájdi súbor uvedený v e-maile, dostaň sa k závislosti, ktorá ten názov obsahuje, aktualizuj ju alebo premenuj svoju metódu a potom sprav nový build.
V Expo pochádza ten názov takmer vždy z natívnej knižnice, len zriedka z tvojho JavaScriptu. 15. októbra 2026 som spustil analytické príkazy z tohto návodu na simulátorovom builde Solys, môjho budíka s minihrami (Expo SDK 57), a na iOS SDK z Xcode 26.2. Ukážem ti, ako čítať e-mail, nájsť vinníka a rozpoznať falošný poplach.
Čo znamená chyba ITMS-90338?
Správa má názov „ITMS-90338: Non-public API usage“. Existuje v troch variantoch podľa toho, čo Apple v tvojom binárnom súbore našiel:
- „references non-public selectors“: názvy metód Objective-C, napríklad
boldFontOfSize:; - „references non-public symbols“: funkcie, zapísané s podčiarkovníkom na začiatku, napríklad
__dyld_get_shared_cache_range; - „contains or inherits from non-public classes“: názov triedy.
Každý variant uvádza cestu a potom zoznam názvov. Text pridáva dve rady: premenovať svoje metódy, ak sa ich názov zhoduje so súkromným API, a odstrániť statickú knižnicu, ktorá ich obsahuje. E-mail zo septembra 2026 navrhuje aj xcrun swift-demangle na sprehľadnenie zakódovaných Swift názvov.
Pravidlo za touto kontrolou je guideline 2.5.1: aplikácia smie používať iba verejné API. Licenčná zmluva Apple Developer Program to opakuje v článku 3.3.1: žiadne volanie súkromného API. Ľudskú kontrolu tohto pravidla podrobne rozoberá návod ku guideline 2.5.1. Tu riešime chybu pri odosielaní.
Rovnako ako pri iných chybách ITMS tvoju appku nikto neotvoril: Apple analyzoval binárny súbor počas spracovania buildu. Apple nezverejňuje žiadny zoznam súkromných API: názvy v tvojom e-maile sú jediný spoľahlivý zoznam.
Čítanie cesty: SDK, alebo tvoj spustiteľný súbor?
Cesta pred zoznamom ti povie, v ktorom súbore hľadať.
Frameworks/Nom.framework/Nom: názov je v pribalenom dynamickom frameworku, teda v konkrétnom SDK. V builde Solys obsahuje tento priečinok 14 frameworkov: Hermes, React Native, predkompilované moduly Expo a knižnicu na obrázky SDWebImage.- Iba názov tvojej appky: názov je v hlavnom spustiteľnom súbore. V Expo spája tvoj natívny kód a pody skompilované zo zdrojákov, predvolene linkované staticky. Vinníkom tak môže byť ktorákoľvek natívna knižnica.
Strom: od uvedeného názvu k oprave
Choď po riadkoch v poradí. Prvý, ktorý sedí na tvoj prípad, ti dá stopu.
| Čo vidíš | Kde hľadať | Oprava |
|---|---|---|
Názov s $s alebo _$s | xcrun swift-demangle | Prejdi strom znova |
| Nenájdený v tvojom IPA | grep v bundli | Pošli build znova |
| Verejný názov na iOS | Hlavičky iOS SDK | Pošli build znova |
API_UNAVAILABLE(ios) | Hlavičky iOS SDK | Aktualizuj balík |
V Frameworks/X | SDK, ktoré dodáva X | Aktualizuj SDK |
| Selektor, tvoja appka | Pody a natívne moduly | Pridaj prefix alebo aktualizuj |
Symbol _nazov, tvoja appka | nm -m, potom pody | Nahraď volanie |
| Trieda, tvoja appka | Tvoje triedy a tvoje pody | Pridaj triede prefix |
Riadky „Pošli build znova“ označujú falošný poplach, ktorému sa venujem nižšie.
Krok 1: otvor odoslaný build
Pracuj so súborom, ktorý si naozaj poslal Apple, nie so svojím projektom. Stiahni IPA zo stránky buildu na expo.dev a na Macu spusti:
unzip -q MyApp.ipa -d ipa
ls ipa/Payload/MyApp.app/Frameworks
otool -L ipa/Payload/MyApp.app/MyApp | grep PrivateFrameworks
Druhý riadok vypíše pribalené frameworky. Tretí hľadá priamy odkaz na súkromný framework Apple: nesmie nič vypísať. Pri Solys otool -L nenájde žiadny súkromný framework, ani v spustiteľnom súbore, ani v 14 frameworkoch.
Krok 2: nájdi súbor, ktorý obsahuje názov
Začni zoširoka. Hľadaj uvedený názov bez úvodných podčiarkovníkov v celom bundli:
grep -rl "dyld_get_shared_cache_range" ipa/Payload/MyApp.app
Príkaz vypíše súbory, ktoré tento text obsahujú. Potom hľadanie spresni podľa typu názvu (selektor, symbol, trieda) v nájdenom súbore, označenom ako Binaire:
strings -a Binaire | grep -x "boldFontOfSize:"
nm -m Binaire | grep "_dyld_get_shared_cache_range"
nm -m Binaire | grep '_OBJC_CLASS_$_NomDeClasse'
Na selektor použi strings, nie nm. Vo frameworku React v Solys nm zobrazuje metódy aj s triedou, napríklad -[RCTRootView initWithBridge:moduleName:initialProperties:], nikdy samotný selektor initWithBridge:. strings ho nájde.
Pri symbole čítaj koniec riadka. V Solys nm -m zobrazí napríklad (undefined) external __dyld_get_image_name (from libSystem): binárny súbor funkciu volá, ale neobsahuje ju, dodáva ju libSystem. Táto konkrétna funkcia je verejná, ako ukazuje ďalší krok.
Krok 3: over, či je názov naozaj súkromný
Hlavičky iOS SDK opisujú verejné API. Pár sekúnd hľadania ti povie, či v nich uvedený názov je a na ktorých platformách. Pri symbole najprv odstráň podčiarkovník pridaný pri kompilácii: z _SCDynamicStoreCreate bude SCDynamicStoreCreate.
SDK=$(xcrun --sdk iphoneos --show-sdk-path)
grep -rn "SCDynamicStoreCreate" "$SDK/usr/include" "$SDK"/System/Library/Frameworks/*/Headers
- októbra 2026 s iOS SDK 26.2 dali štyri názvy zo skutočných e-mailov ITMS-90338 tento výsledok:
| Uvedený názov | V iOS SDK | Výklad |
|---|---|---|
| _dyld_get_shared_cache_range | Chýba | Súkromné API |
| boldFontOfSize: | Chýba | Súkromné alebo kolízia |
| SCDynamicStoreCreate | API_UNAVAILABLE(ios) | Iba macOS |
| isMainFrame | Vlastnosť WebKitu | Verejné |
Názov, ktorý tam je a je dostupný na iOS, ukazuje na falošný poplach. Chýbajúci názov ukazuje na súkromné API alebo kolíziu. Dve obmedzenia: verejné API dostupné iba vo Swifte sa v týchto hlavičkách neobjaví a pri accessore ako setDelegate: hľadaj vlastnosť delegate.
Krok 4: dostaň sa k balíku
Ak cesta uvádza framework, jeho názov ťa dovedie k podu a potom k npm balíku:
grep -n "NomDuFramework" ios/Podfile.lock
npm explain nom-du-paquet
npm explain ti povie, ktorá závislosť ho nainštalovala, ak si ho nikdy nepridal sám.
Ak cesta uvádza spustiteľný súbor, hľadaj názov v natívnych zdrojákoch a potom v podoch:
grep -rl --include='*.m' --include='*.mm' --include='*.swift' --include='*.h' \
"boldFontOfSize" node_modules modules
grep -rl "boldFontOfSize" ios/Pods
Zoznam priečinkov si uprav: modules je priečinok lokálnych modulov Expo. Priečinok ios/Pods sa objaví po npx expo prebuild -p ios, ktorý na Macu nainštaluje aj pody. Pozor: tento príkaz môže priečinok ios vytvoriť nanovo. Ak si ho upravoval ručne, pracuj na kópii.
Hľadanie v ios/Pods je rovnako dôležité ako hľadanie v zdrojákoch. V Solys obsahuje tento priečinok 15 predkompilovaných frameworkov vo formáte .xcframework: moduly Expo, Hermes, React Native a SDK tretích strán. Hľadanie obmedzené na zdrojové súbory by ich kód minulo.
Typické príčiny
SDK tretej strany, príliš staré alebo príliš nové. V septembri 2026 jeden Flutter vývojár nahlásil zamietnutie kvôli bezpečnostnému SDK: jeho verzia 8.2.3 volala __dyld_get_shared_cache_range. Verzia 8.2.2 prešla a vydavateľ odporučil vrátiť sa k nej, kým nebude oprava.
Natívny modul, ktorý volá nezdokumentované API. Tvoj vlastný modul, plugin alebo malá knižnica môže používať internú metódu UIKitu nájdenú na fóre. Kontrola ju odhalí podľa názvu.
Kolízia názvov. Tvoja metóda alebo trieda náhodou nesie názov súkromného API Apple. Správa s tým počíta a žiada ťa ju premenovať. Apple odporúča pridávať prefix k metódam pridaným do jeho tried, napríklad tri malé písmená a za nimi podčiarkovník.
API verejné na macOS, nie na iOS. V roku 2024 bola appka v .NET MAUI zamietnutá kvôli _SCDynamicStoreCreate. Apple túto funkciu dokumentuje, ale iba pre macOS, a hlavička iOS SDK ju označuje API_UNAVAILABLE(ios, tvos, watchos).
Oprav to, neobchádzaj
- Aktualizuj závislosť. Pri balíkoch, ktoré Expo sleduje,
npx expo install --checkupozorní na tie, ktoré nesedia s tvojím SDK, podľa dokumentácie Expo CLI. Pri ostatných si prečítaj changelog. - Vráť sa k predchádzajúcej verzii, ak názov priniesla tá nová, a daj vedieť vydavateľovi.
- Nahraď alebo odstráň opustenú knižnicu.
- Premenuj svoju metódu alebo triedu a pridaj jej prefix.
Názov neskrývaj. Rozdelenie reťazca alebo volanie metódy oklukou použitie skryje, ale neopraví. Stále ho zakazuje pravidlo 2.5.1 aj zmluva, a riziku je potom vystavený tvoj účet.
Potom sprav nový build s novým číslom buildu. Aktualizácia na diaľku nestačí: názov je v skompilovanom natívnom kóde. Pred odoslaním spusti krok 2 znova na novom IPA. Názov sa už nesmie objaviť.
Keď ide o falošný poplach
Kontrola Apple sa niekedy mýli. 6. júna 2022 dostali React Native a Flutter appky ITMS-90338 kvôli verejným názvom z WebKitu, ako setNavigationDelegate: alebo isMainFrame, a to aj pri takmer nezmenených aktualizáciách. Na druhý deň inžinier Apple napísal, že problém je na strane validácie vyriešený, a vyzval na opätovné odoslanie buildov. Vlákno je uložené v GitHub repozitári Expo.
Na falošný poplach ukazujú tri indície naraz:
- build sa podobá na posledný prijatý build;
- krok 2 názov nenájde alebo krok 3 ukáže, že je na iOS verejný;
- ostatní vývojári hlásia v ten istý deň rovnakú chybu na fórach Apple.
V takom prípade pozri stav služieb Apple a potom pošli build znova s novým číslom. Ak chyba pretrváva, napíš podpore pre vývojárov Apple a prilož celý e-mail. Kolízia názvov však v očiach Apple falošný poplach nie je: premenuj.
Pred ďalším odoslaním
Aj ostatné chyby ITMS majú svoj návod: ITMS-90725 pre verziu Xcode, ITMS-91053 pre privacy manifest a ITMS-90034 pre podpis. Keď je build prijatý, pred kontrolou si ho nainštaluj cez TestFlight.
Zamietnutia od reviewera si vyžadujú viac nadhľadu: postup nájdeš na stránke appka zamietnutá Apple a najčastejšie dôvody v článku prečo Apple zamieta appky.
Na kontrolu tvojich podkladov pred odoslaním je tu Review Kit: obsahuje môj checklist a skills pre Claude Code, ktoré prejdú tvoj projekt. Ak sa ti odosielanie zasekne a chceš ľudský pohľad, rezervuj si so mnou hodinu: prejdeme tvoj projekt cez videohovor, na tvojej obrazovke. A ak chystáš svoje prvé vydanie, sprav si bezplatnú diagnostiku: zoradí kroky do správneho poradia a pošle ti môj checklist proti zamietnutiu od Apple.
Často kladené otázky
Je ITMS-90338 zamietnutie od App Review?
Nie. Je to automatická kontrola počas spracovania buildu, ešte pred akoukoľvek ľudskou kontrolou. Zamietnutý build sa nedostane ani do TestFlightu, ani na kontrolu. Súkromné API, ktoré neskôr odhalí reviewer, spadá pod guideline 2.5.1.
Dá sa ITMS-90338 opraviť aktualizáciou na diaľku?
Nie. Uvedené názvy sú v skompilovanom natívnom kóde binárneho súboru. Aktualizácia na diaľku mení iba JavaScript a zdroje. Oprav závislosť, sprav nový build a pošli ho znova.
Prečo Apple uvádza metódy, ktoré som nikdy nenapísal?
Pretože pochádzajú z pribalenej knižnice alebo z kolízie: niektorá závislosť deklaruje metódu s názvom súkromného API. Apple číta názvy v binárnom súbore, nie tvoj zdrojový kód. K balíku sa dostaneš cez grep a npm explain.
Ako zistím, či je API na iOS verejné?
Vyhľadaj jeho názov v hlavičkách iOS SDK, ktorých cestu ti dá xcrun --sdk iphoneos --show-sdk-path, a pozri si jeho dostupnosť. Uvádza ju aj stránka dokumentácie Apple. Funkcia zdokumentovaná iba pre macOS nie je na iPhone verejná.
Treba po oprave zmeniť číslo buildu?
Áno. Nechaj EAS, nech ho zvýši: číslo, ktoré už bolo pre tú istú verziu odoslané, môže byť zamietnuté s chybou ITMS-90189.

