ITMS-90338: popravi »Non-public API usage« v Expu
Avtor: Mehdi Azizi
Objavljeno , 9 min
ITMS-90338: tvoj build omenja metodo, funkcijo ali razred, ki ga Apple šteje za zasebnega. Najdi odvisnost, jo posodobi in naredi nov build.
ITMS-90338 je Applova samodejna kontrola tvojega builda. Pove, da se tvoja binarna datoteka sklicuje na API-je, ki jih Apple šteje za zasebne: metode Objective-C, funkcije ali razrede. Popravek: poišči datoteko, navedeno v e-pošti, sledi do odvisnosti, ki vsebuje ime, jo posodobi ali preimenuj svojo metodo, nato naredi nov build.
Pri Expu ime skoraj vedno pride iz native knjižnice, redko iz tvojega JavaScripta. 15. oktobra 2026 sem ukaze za analizo iz tega vodnika zagnal na simulatorskem buildu Solysa, moje budilke z mini igrami (Expo SDK 57), in na iOS SDK-ju Xcode 26.2. Tukaj je, kako prebrati e-pošto, najti krivca in prepoznati lažni alarm.
Kaj pomeni napaka ITMS-90338?
Sporočilo ima naslov »ITMS-90338: Non-public API usage«. Obstaja v treh različicah, odvisno od tega, kaj je Apple našel v tvoji binarni datoteki:
- »references non-public selectors«: imena metod Objective-C, na primer
boldFontOfSize:; - »references non-public symbols«: funkcije, zapisane s podčrtajem spredaj, na primer
__dyld_get_shared_cache_range; - »contains or inherits from non-public classes«: ime razreda.
Vsaka različica navede pot in nato seznam imen. Besedilo doda dva nasveta: preimenuj svoje metode, če se njihovo ime ujema z zasebnim API-jem, in odstrani statično knjižnico, ki jih vsebuje. E-pošta iz septembra 2026 predlaga tudi xcrun swift-demangle, da kodirana imena Swift postanejo berljiva.
Pravilo za to kontrolo je smernica 2.5.1: aplikacija sme uporabljati samo javne API-je. Licenčna pogodba Apple Developer Program to ponovi v členu 3.3.1: nobenega klica zasebnega API-ja. Človeški pregled tega pravila je podrobno opisan v vodniku za smernico 2.5.1. Tukaj obravnavamo napako pri pošiljanju.
Tako kot pri drugih napakah ITMS tvoje aplikacije ni odprl nihče: Apple je binarno datoteko analiziral med obdelavo builda. Apple ne objavlja seznama zasebnih API-jev: imena v tvoji e-pošti so edini zanesljiv seznam.
Branje poti: SDK ali tvoja izvršljiva datoteka?
Pot, zapisana pred seznamom, ti pove, v kateri datoteki iskati.
Frameworks/Nom.framework/Nom: ime je v vgrajenem dinamičnem ogrodju, torej v točno določenem SDK-ju. V buildu Solysa ta mapa vsebuje 14 ogrodij: Hermes, React Native, module Expo, ki so dostavljeni že prevedeni, in knjižnico za slike SDWebImage.- Samo ime tvoje aplikacije: ime je v glavni izvršljivi datoteki. Pri Expu ta združuje tvojo native kodo in pode, prevedene iz izvorne kode, privzeto statično povezane. Kriva je lahko katera koli native knjižnica.
Drevo: od navedenega imena do popravka
Vrstice preglej po vrsti. Prva, ki ustreza tvojemu primeru, ti da smer.
| Kaj prebereš | Kje iskati | Popravek |
|---|---|---|
Ime z $s ali _$s | xcrun swift-demangle | Znova skozi drevo |
| Ni ga v tvojem IPA | grep po bundlu | Ponovno pošlji build |
| Javno ime na iOS | Glave iOS SDK-ja | Ponovno pošlji build |
API_UNAVAILABLE(ios) | Glave iOS SDK-ja | Posodobi paket |
V Frameworks/X | SDK, ki prinaša X | Posodobi SDK |
| Selektor, tvoja aplikacija | Podi in native moduli | Dodaj predpono ali posodobi |
Simbol _nom, tvoja app | nm -m, nato podi | Zamenjaj klic |
| Razred, tvoja aplikacija | Tvoji razredi in podi | Razredu dodaj predpono |
Vrstice »Ponovno pošlji build« označujejo lažni alarm, ki ga obravnavam spodaj.
1. korak: odpri poslani build
Delaj na datoteki, ki je bila dejansko poslana Applu, ne na svojem projektu. Prenesi IPA s strani builda na expo.dev, nato na Macu zaženi:
unzip -q MyApp.ipa -d ipa
ls ipa/Payload/MyApp.app/Frameworks
otool -L ipa/Payload/MyApp.app/MyApp | grep PrivateFrameworks
Druga vrstica izpiše vgrajena ogrodja. Tretja išče neposredno povezavo do Applovega zasebnega ogrodja: ne sme izpisati ničesar. Pri Solysu otool -L ne najde nobenega zasebnega ogrodja, ne v izvršljivi datoteki ne v 14 ogrodjih.
2. korak: najdi datoteko, ki vsebuje ime
Začni široko. Navedeno ime, brez začetnih podčrtajev, išči po celotnem bundlu:
grep -rl "dyld_get_shared_cache_range" ipa/Payload/MyApp.app
Ukaz izpiše datoteke, ki vsebujejo to besedilo. Nato iskanje zoži glede na vrsto imena (selektor, simbol, razred), na najdeni datoteki, označeni kot Binaire:
strings -a Binaire | grep -x "boldFontOfSize:"
nm -m Binaire | grep "_dyld_get_shared_cache_range"
nm -m Binaire | grep '_OBJC_CLASS_$_NomDeClasse'
Za selektor uporabi strings, ne nm. Na ogrodju React v Solysu nm izpiše metode z razredom, na primer -[RCTRootView initWithBridge:moduleName:initialProperties:], nikoli samega selektorja initWithBridge:. strings ga najde.
Pri simbolu preberi konec vrstice. Pri Solysu nm -m izpiše na primer (undefined) external __dyld_get_image_name (from libSystem): binarna datoteka funkcijo kliče, ne da bi jo vsebovala, priskrbi jo libSystem. Ta funkcija je javna, kot pokaže naslednji korak.
3. korak: preveri, ali je ime res zasebno
Glave iOS SDK-ja opisujejo javne API-je. Iskanje v nekaj sekundah pove, ali je navedeno ime v njih in na katerih platformah. Pri simbolu najprej odstrani podčrtaj, dodan pri prevajanju: _SCDynamicStoreCreate postane SCDynamicStoreCreate.
SDK=$(xcrun --sdk iphoneos --show-sdk-path)
grep -rn "SCDynamicStoreCreate" "$SDK/usr/include" "$SDK"/System/Library/Frameworks/*/Headers
- oktobra 2026 so s SDK-jem iOS 26.2 štiri imena iz resničnih e-poštnih sporočil ITMS-90338 dala tole:
| Navedeno ime | V iOS SDK-ju | Razlaga |
|---|---|---|
| _dyld_get_shared_cache_range | Ni ga | Zasebni API |
| boldFontOfSize: | Ni ga | Zasebno ali kolizija |
| SCDynamicStoreCreate | API_UNAVAILABLE(ios) | Samo macOS |
| isMainFrame | Lastnost WebKita | Javno |
Ime, ki obstaja in je na voljo na iOS, kaže na lažni alarm. Ime, ki ga ni, kaže na zasebni API ali kolizijo. Dve omejitvi: API, ki je javen samo v Swiftu, se v teh glavah ne pojavi, za dostopno metodo, kot je setDelegate:, pa išči lastnost delegate.
4. korak: sledi do paketa
Če pot navaja ogrodje, te njegovo ime pripelje do poda in nato do paketa npm:
grep -n "NomDuFramework" ios/Podfile.lock
npm explain nom-du-paquet
npm explain pove, katera odvisnost ga je namestila, če ga nisi nikoli dodal sam.
Če pot navaja izvršljivo datoteko, išči ime v native izvorni kodi in nato v podih:
grep -rl --include='*.m' --include='*.mm' --include='*.swift' --include='*.h' \
"boldFontOfSize" node_modules modules
grep -rl "boldFontOfSize" ios/Pods
Seznam map prilagodi: modules je mapa lokalnih modulov Expo. Mapa ios/Pods se pojavi po npx expo prebuild -p ios, ki na Macu tudi namesti pode. Pozor: ukaz lahko na novo ustvari mapo ios. Če si jo ročno spreminjal, delaj na kopiji.
Iskanje v ios/Pods je enako pomembno kot iskanje v izvorni kodi. Pri Solysu ta mapa vsebuje 15 že prevedenih ogrodij v formatu .xcframework: module Expo, Hermes, React Native in SDK-je tretjih oseb. Iskanje samo po izvornih datotekah bi njihovo kodo zgrešilo.
Tipični vzroki
SDK tretje osebe, prestar ali prenov. Septembra 2026 je razvijalec Flutterja prijavil zavrnitev zaradi varnostnega SDK-ja: njegova različica 8.2.3 je klicala __dyld_get_shared_cache_range. Različica 8.2.2 je šla skozi in izdajatelj je svetoval, naj se do popravka vrne nanjo.
Native modul, ki kliče nedokumentiran API. Tvoj modul, vtičnik ali majhna knjižnica lahko uporablja notranjo metodo UIKita, najdeno na forumu. Kontrola jo prepozna po imenu.
Kolizija imen. Tvoja metoda ali razred po naključju nosi ime Applovega zasebnega API-ja. Sporočilo to predvideva in te prosi, da ga preimenuješ. Apple priporoča, da metodam, dodanim njegovim razredom, dodaš predpono, na primer tri male črke in podčrtaj.
API, javen na macOS, ne pa na iOS. Leta 2024 je bila aplikacija .NET MAUI zavrnjena zaradi _SCDynamicStoreCreate. Apple to funkcijo sicer dokumentira, a samo za macOS, glava iOS SDK-ja pa jo označi z API_UNAVAILABLE(ios, tvos, watchos).
Popravi, ne obidi
- Posodobi odvisnost. Za pakete, ki jih spremlja Expo,
npx expo install --checkpo dokumentaciji Expo CLI označi tiste, ki se ne ujemajo s tvojim SDK-jem. Za druge preberi dnevnik sprememb. - Vrni se na prejšnjo različico, če je ime prinesla nova, in obvesti izdajatelja.
- Zamenjaj ali odstrani opuščeno knjižnico.
- Preimenuj svojo metodo ali razred s predpono.
Imena ne skrivaj. Razbijanje niza ali klicanje metode po ovinku uporabo skrije, ne popravi. Še vedno jo prepovedujeta pravilo 2.5.1 in pogodba, izpostavljen pa je potem tvoj račun.
Nato naredi nov build z novo številko builda. Posodobitev na daljavo ni dovolj: ime je v prevedeni native kodi. Pred pošiljanjem znova zaženi 2. korak na novem IPA. Ime se ne sme več pojaviti.
Ko gre za lažni alarm
Applova kontrola se včasih zmoti. 6. junija 2022 so aplikacije React Native in Flutter dobile ITMS-90338 zaradi javnih imen WebKita, kot sta setNavigationDelegate: ali isMainFrame, tudi pri skoraj nespremenjenih posodobitvah. Naslednji dan je Applov inženir zapisal, da je težava na strani validacije odpravljena, in pozval k ponovnemu pošiljanju buildov. Nit je ohranjena v repozitoriju Expo na GitHubu.
Trije znaki skupaj kažejo na lažni alarm:
- build je podoben zadnjemu sprejetemu buildu;
-
- korak imena ne najde ali 3. korak pokaže, da je na iOS javno;
- drugi razvijalci isti dan na Applovih forumih poročajo o isti napaki.
V tem primeru preveri stanje Applovih storitev, nato pošlji build z novo številko. Če napaka ostane, piši Applovi podpori za razvijalce in priloži celotno e-pošto. Kolizija imen pa za Apple ni lažni alarm: preimenuj.
Pred naslednjim pošiljanjem
Tudi druge napake ITMS imajo svoj vodnik: ITMS-90725 za različico Xcode, ITMS-91053 za manifest zasebnosti in ITMS-90034 za podpis. Ko je build sprejet, ga pred pregledom namesti prek TestFlighta.
Zavrnitve s strani pregledovalca zahtevajo več premisleka: postopek je na strani aplikacija, ki jo je Apple zavrnil, najpogostejši razlogi pa so v članku zakaj Apple zavrne aplikacijo.
Da pred pošiljanjem preveriš svojo vlogo, Review Kit združuje moj kontrolni seznam in skille za Claude Code, ki pregledajo tvoj projekt. Če se pošiljanje zatakne in želiš človeški pogled, rezerviraj uro z mano: projekt pregledava prek videoklica, na tvojem zaslonu. In če pripravljaš prvo objavo, opravi brezplačno diagnostiko: uredi korake po vrsti in ti pošlje moj kontrolni seznam proti Applovim zavrnitvam.
Pogosta vprašanja
Je ITMS-90338 zavrnitev App Review?
Ne. Gre za samodejno kontrolo med obdelavo builda, pred kakršnim koli človeškim pregledom. Zavrnjeni build ne pride ne v TestFlight ne v pregled. Zasebni API, ki ga pozneje opazi pregledovalec, pa spada pod smernico 2.5.1.
Ali lahko ITMS-90338 popravim s posodobitvijo na daljavo?
Ne. Navedena imena so v prevedeni native kodi binarne datoteke. Posodobitev na daljavo spremeni samo JavaScript in vire. Popravi odvisnost, naredi nov build in ga pošlji.
Zakaj Apple navaja metode, ki jih nisem nikoli napisal?
Ker prihajajo iz vgrajene knjižnice ali iz kolizije: odvisnost deklarira metodo, ki nosi ime zasebnega API-ja. Apple bere imena v binarni datoteki, ne tvoje izvorne kode. Do paketa prideš z grep in npm explain.
Kako vem, ali je API na iOS javen?
Njegovo ime poišči v glavah iOS SDK-ja, katerih pot ti da xcrun --sdk iphoneos --show-sdk-path, in preberi razpoložljivost. To navaja tudi Applova stran z dokumentacijo. Funkcija, dokumentirana samo za macOS, na iPhonu ni javna.
Ali moram po popravku spremeniti številko builda?
Da. Naj jo EAS poveča: številka, ki je bila za isto različico že poslana, je lahko zavrnjena z ITMS-90189.

