ITMS-90338 javítása: Non-public API usage Expóval
Írta: Mehdi Azizi
Megjelent: , 9 p
ITMS-90338: a buildod egy Apple szerint privát API-ra hivatkozik. Keresd meg a hibás függőséget, frissítsd, és buildeld újra.
Az ITMS-90338 az Apple automatikus ellenőrzése, ami a buildodon fut le. Azt jelenti, hogy a binárisod olyan API-kra hivatkozik, amelyeket az Apple privátnak tart: Objective-C metódusokra, függvényekre vagy osztályokra. A javítás: keresd meg az e-mailben megnevezett fájlt, kövesd vissza a nevet tartalmazó függőségig, frissítsd azt vagy nevezd át a saját metódusodat, aztán készíts új buildet.
Expónál a név szinte mindig egy natív könyvtárból jön, ritkán a JavaScript-kódodból. 2026. október 15-én lefuttattam az útmutató elemző parancsait a Solys (az ébresztőórám minijátékokkal, Expo SDK 57) szimulátoros buildjén és a Xcode 26.2 iOS SDK-ján. Megmutatom, hogyan olvasd az e-mailt, hogyan találd meg a bűnöst, és hogyan ismerd fel a téves riasztást.
Mit jelent az ITMS-90338 hiba?
Az üzenet címe: „ITMS-90338: Non-public API usage”. Három változata van, attól függően, mit talált az Apple a binárisodban:
- „references non-public selectors”: Objective-C metódusnevek, például
boldFontOfSize:; - „references non-public symbols”: alsó vonallal kezdődő függvények, például
__dyld_get_shared_cache_range; - „contains or inherits from non-public classes”: egy osztálynév.
Mindegyik változat megad egy elérési utat, utána a nevek listáját. A szöveg két tanácsot is ad: nevezd át a metódusaidat, ha a nevük egy privát API-val egyezik, és távolítsd el az őket tartalmazó statikus könyvtárat. Egy 2026 szeptemberi e-mail az xcrun swift-demangle parancsot is javasolja, hogy a kódolt Swift-nevek olvashatók legyenek.
Az ellenőrzés mögötti szabály a 2.5.1-es guideline: egy app csak nyilvános API-kat használhat. Az Apple Developer Program licencszerződése ezt a 3.3.1-es pontban megismétli: privát API hívása tilos. Ennek a szabálynak az emberi review-ját a 2.5.1-es guideline útmutatója részletezi. Itt a feltöltési hibával foglalkozunk.
A többi ITMS-hibához hasonlóan senki nem nyitotta meg az appodat: az Apple a build feldolgozása közben elemezte a binárist. Az Apple nem tesz közzé listát a privát API-król: az e-mailedben szereplő nevek az egyetlen megbízható lista.
Az elérési út: SDK vagy a futtatható fájlod?
A lista előtt álló elérési út megmondja, melyik fájlban keress.
Frameworks/Nom.framework/Nom: a név egy beágyazott dinamikus frameworkben van, tehát egy konkrét SDK-ban. A Solys buildjében ez a mappa 14 frameworköt tartalmaz: Hermest, React Native-ot, előre lefordítva szállított Expo-modulokat és az SDWebImage képkönyvtárat.- Csak az appod neve: a név a fő futtatható fájlban van. Expónál ez egyesíti a natív kódodat és a forrásból fordított podokat, amelyek alapértelmezésben statikusan linkelődnek. Ilyenkor bármelyik natív könyvtár lehet a hibás.
A döntési fa: a megnevezett névtől a javításig
Haladj sorban a sorokon. Az első, ami illik az esetedre, megadja az irányt.
| Amit látsz | Hol keress | Javítás |
|---|---|---|
$s vagy _$s kezdetű név | xcrun swift-demangle | Kezdd újra a fát |
| Nincs meg az IPA-ban | grep a bundle-ön | Küldj be újra egy buildet |
| Nyilvános név iOS-en | Az iOS SDK fejlécei | Küldj be újra egy buildet |
API_UNAVAILABLE(ios) | Az iOS SDK fejlécei | Frissítsd a csomagot |
A Frameworks/X mappában | Az X-et szállító SDK | Frissítsd az SDK-t |
| Szelektor, az appod | Podok és natív modulok | Prefixáld vagy frissítsd |
_nom szimbólum, az appod | nm -m, aztán a podok | Cseréld le a hívást |
| Osztály, az appod | A saját osztályaid és podjaid | Prefixáld az osztályt |
A „Küldj be újra egy buildet” sorok téves riasztást jeleznek, erről lentebb lesz szó.
1. lépés: nyisd meg a beküldött buildet
A ténylegesen az Apple-nek elküldött fájlon dolgozz, ne a projekteden. Töltsd le az IPA-t a build oldaláról az expo.dev-en, aztán futtasd a Maceden:
unzip -q MonApp.ipa -d ipa
ls ipa/Payload/MonApp.app/Frameworks
otool -L ipa/Payload/MonApp.app/MonApp | grep PrivateFrameworks
A második sor kilistázza a beágyazott frameworköket. A harmadik közvetlen hivatkozást keres az Apple valamelyik privát frameworkjére: semmit nem szabad kiírnia. A Solysnál az otool -L nem talál privát frameworköt, sem a futtatható fájlban, sem a 14 frameworkben.
2. lépés: keresd meg a nevet tartalmazó fájlt
Kezdd tágan. Keresd a megnevezett nevet, az elején lévő alsó vonalak nélkül, a teljes bundle-ben:
grep -rl "dyld_get_shared_cache_range" ipa/Payload/MonApp.app
A parancs kilistázza a szöveget tartalmazó fájlokat. Utána szűkíts a név típusa szerint (szelektor, szimbólum, osztály) a megtalált fájlon, amit itt Binaire jelöl:
strings -a Binaire | grep -x "boldFontOfSize:"
nm -m Binaire | grep "_dyld_get_shared_cache_range"
nm -m Binaire | grep '_OBJC_CLASS_$_NomDeClasse'
Szelektorhoz a strings parancsot használd, ne az nm-et. A Solys React frameworkjén az nm az osztályukkal együtt mutatja a metódusokat, például -[RCTRootView initWithBridge:moduleName:initialProperties:], de soha nem magában az initWithBridge: szelektort. A strings megtalálja.
Szimbólumnál a sor végét olvasd. A Solysnál az nm -m például ezt írja ki: (undefined) external __dyld_get_image_name (from libSystem). A bináris meghívja a függvényt, de nem tartalmazza, a libSystem biztosítja. Ez a függvény nyilvános, ahogy a következő lépés megmutatja.
3. lépés: ellenőrizd, tényleg privát-e a név
Az iOS SDK fejlécei írják le a nyilvános API-kat. Pár másodperces kereséssel kiderül, szerepel-e bennük a megnevezett név, és mely platformokon. Szimbólumnál előbb vedd le a fordításkor hozzáadott alsó vonalat: a _SCDynamicStoreCreate így SCDynamicStoreCreate lesz.
SDK=$(xcrun --sdk iphoneos --show-sdk-path)
grep -rn "SCDynamicStoreCreate" "$SDK/usr/include" "$SDK"/System/Library/Frameworks/*/Headers
- október 15-én, az iOS 26.2 SDK-val ezt adja négy név, amelyek valódi ITMS-90338-as e-mailekből származnak:
| Megnevezett név | Az iOS SDK-ban | Értelmezés |
|---|---|---|
| _dyld_get_shared_cache_range | Nincs benne | Privát API |
| boldFontOfSize: | Nincs benne | Privát vagy névütközés |
| SCDynamicStoreCreate | API_UNAVAILABLE(ios) | Csak macOS |
| isMainFrame | WebKit-tulajdonság | Nyilvános |
Ha a név benne van és iOS-en elérhető, az téves riasztásra utal. Ha nincs benne, az privát API-ra vagy névütközésre. Két korlát: egy csak Swiftben nyilvános API nem jelenik meg ezekben a fejlécekben, és egy olyan accessornál, mint a setDelegate:, a delegate tulajdonságra keress.
4. lépés: kövesd vissza a csomagig
Ha az elérési út frameworköt nevez meg, a neve elvezet a podhoz, onnan az npm-csomaghoz:
grep -n "NomDuFramework" ios/Podfile.lock
npm explain nom-du-paquet
Az npm explain megmondja, melyik függőség telepítette, ha te magad sosem adtad hozzá.
Ha az elérési út a futtatható fájlt nevezi meg, keresd a nevet a natív forrásokban, aztán a podokban:
grep -rl --include='*.m' --include='*.mm' --include='*.swift' --include='*.h' \
"boldFontOfSize" node_modules modules
grep -rl "boldFontOfSize" ios/Pods
Igazítsd a mappák listáját: a modules a helyi Expo-modulok mappája. Az ios/Pods mappa az npx expo prebuild -p ios után jelenik meg, ami Macen a podokat is telepíti. Figyelem: ez újra létrehozhatja az ios mappát. Ha kézzel módosítottad, egy másolaton dolgozz.
Az ios/Pods mappában keresni ugyanolyan fontos, mint a forrásokban. A Solysnál ez a mappa 15, előre lefordítva szállított frameworköt tartalmaz .xcframework formátumban: Expo-modulokat, Hermest, React Native-ot és harmadik féltől származó SDK-kat. A csak forrásfájlokra szűkített keresés elmenne a kódjuk mellett.
A tipikus okok
Egy harmadik féltől származó SDK, ami túl régi vagy túl új. 2026 szeptemberében egy Flutter-fejlesztő egy biztonsági SDK miatti elutasítást jelzett: a 8.2.3-as verzió meghívta a __dyld_get_shared_cache_range függvényt. A 8.2.2-es átment, és a fejlesztő cég azt tanácsolta, hogy térjenek vissza rá, amíg nincs javítás.
Egy natív modul, ami nem dokumentált API-t hív. A saját modulod, egy plugin vagy egy kis könyvtár használhat egy fórumon talált belső UIKit-metódust. Az ellenőrzés a neve alapján kiszúrja.
Névütközés. A metódusod vagy az osztályod véletlenül egy privát Apple API nevét viseli. Az üzenet számol ezzel, és arra kér, hogy nevezd át. Az Apple azt ajánlja, hogy prefixáld az osztályaihoz hozzáadott metódusokat, például három kisbetűvel és egy alsó vonallal.
Egy API, ami macOS-en nyilvános, iOS-en nem. 2024-ben egy .NET MAUI appot a _SCDynamicStoreCreate miatt utasítottak el. Az Apple dokumentálja ezt a függvényt, de csak macOS-re, és az iOS SDK fejléce API_UNAVAILABLE(ios, tvos, watchos) jelöléssel látja el.
Javítás kerülőutak nélkül
- Frissítsd a függőséget. Az Expo által követett csomagoknál az
npx expo install --checkjelzi azokat, amelyek nem illenek az SDK-dhoz, az Expo CLI dokumentációja szerint. A többinél olvasd el a változásnaplót. - Térj vissza az előző verzióra, ha az új hozta be a nevet, és szólj a fejlesztőnek.
- Cseréld le vagy távolítsd el az elhagyott könyvtárat.
- Nevezd át a metódusodat vagy az osztályodat, egy prefixszel.
Ne rejtsd el a nevet. Ha szétdarabolod a stringet, vagy kerülőúton hívod meg a metódust, azzal elrejted a használatot, de nem javítod. Továbbra is tiltja a 2.5.1-es szabály és a szerződés, és ilyenkor a fiókod kerül veszélybe.
Utána készíts új buildet új buildszámmal. A távoli frissítés nem elég: a név a lefordított natív kódban van. Beküldés előtt futtasd le újra a 2. lépést az új IPA-n. A név nem szerepelhet benne.
Amikor téves riasztásról van szó
Az Apple ellenőrzése néha téved. 2022. június 6-án React Native és Flutter appok kaptak ITMS-90338-at nyilvános WebKit-nevek miatt, mint a setNavigationDelegate: vagy az isMainFrame, még szinte változatlan frissítéseknél is. Másnap egy Apple-mérnök azt írta, hogy a problémát a validáció oldalán megoldották, és arra kért mindenkit, hogy küldje be újra a buildjeit. A szál megmaradt az Expo GitHub-repójában.
Ha ez a három jel együtt áll fenn, az téves riasztásra utal:
- a build hasonlít az utolsó elfogadott buildre;
- a 2. lépés nem találja a nevet, vagy a 3. lépés szerint iOS-en nyilvános;
- más fejlesztők ugyanazon a napon ugyanezt a hibát jelzik az Apple fórumain.
Ilyenkor nézd meg az Apple szolgáltatásainak állapotát, aztán küldj be újra egy buildet új számmal. Ha a hiba megmarad, írj az Apple fejlesztői supportjának a teljes e-maillel. A névütközés viszont az Apple szemében nem téves riasztás: nevezd át.
A következő beküldés előtt
A többi ITMS-hibának is megvan a saját útmutatója: ITMS-90725 a Xcode-verzióhoz, ITMS-91053 az adatvédelmi manifesthez és ITMS-90034 az aláíráshoz. Ha a buildet elfogadták, telepítsd TestFlighttal a review előtt.
A reviewer általi elutasítások több rálátást igényelnek: a teendőket az Apple által elutasított app oldalon találod, a leggyakoribb okokat pedig a miért utasítja el az Apple az appodat cikkben.
Ha beküldés előtt ellenőriznéd az anyagodat, a Review Kit tartalmazza a checklistemet és Claude Code skilleket, amelyek átnézik a projektedet. Ha elakadt a beküldésed, és emberi szemre van szükséged, foglalj velem egy órát: videóhívásban, a te képernyődön nézzük át a projektedet. Ha pedig az első megjelenésedre készülsz, csináld meg az ingyenes diagnosztikát: sorba rakja a lépéseket, és elküldi neked az Apple-elutasítás elleni checklistemet.
Gyakori kérdések
Az ITMS-90338 az App Review elutasítása?
Nem. Ez egy automatikus ellenőrzés, ami a build feldolgozása közben fut, még minden emberi review előtt. Az elutasított build nem kerül se TestFlightba, se review-ra. Ha egy privát API-t később egy reviewer szúr ki, az a 2.5.1-es guideline alá tartozik.
Javítható az ITMS-90338 távoli frissítéssel?
Nem. A megnevezett nevek a bináris lefordított natív kódjában vannak. A távoli frissítés csak a JavaScriptet és az erőforrásokat változtatja meg. Javítsd a függőséget, készíts új buildet, és küldd be újra.
Miért említ az Apple olyan metódusokat, amelyeket sosem írtam?
Mert egy beágyazott könyvtárból származnak, vagy névütközésről van szó: egy függőség olyan metódust deklarál, ami egy privát API nevét viseli. Az Apple a binárisban lévő neveket olvassa, nem a forráskódodat. Kövesd vissza a csomagig a grep és az npm explain segítségével.
Honnan tudhatom, hogy egy API nyilvános-e iOS-en?
Keresd a nevét az iOS SDK fejléceiben (az elérési útjukat az xcrun --sdk iphoneos --show-sdk-path adja meg), és nézd meg az elérhetőségét. Az Apple dokumentációs oldala is jelzi. Egy csak macOS-re dokumentált függvény iPhone-on nem nyilvános.
Meg kell változtatni a buildszámot a javítás után?
Igen. Hagyd, hogy az EAS növelje: egy ugyanahhoz a verzióhoz már beküldött számot ITMS-90189 hibával elutasíthatnak.

