ITMS-90338: Non-public API usage -virheen korjaus Expolla
Kirjoittaja: Mehdi Azizi
Julkaistu , 9 min
ITMS-90338: buildisi viittaa metodiin, funktioon tai luokkaan, jota Apple pitää yksityisenä. Etsi syyllinen riippuvuus, päivitä se ja tee uusi build.
ITMS-90338 on Applen automaattinen tarkistus, joka ajetaan buildillesi. Se kertoo, että binäärisi viittaa rajapintoihin, joita Apple pitää yksityisinä: Objective-C-metodeihin, funktioihin tai luokkiin. Korjaus: etsi sähköpostissa mainittu tiedosto, jäljitä riippuvuus, joka sisältää nimen, päivitä se tai nimeä oma metodisi uudelleen ja tee sitten uusi build.
Expolla nimi tulee lähes aina natiivikirjastosta, harvoin JavaScriptistäsi. Ajoin 15. lokakuuta 2026 tämän oppaan analyysikomennot Solysin simulaattoribuildille (Solys on minipelejä sisältävä herätyskelloni, Expo SDK 57) sekä Xcode 26.2:n iOS SDK:lle. Näin luet sähköpostin, löydät syyllisen ja tunnistat väärän hälytyksen.
Mitä ITMS-90338-virhe tarkoittaa?
Viestin otsikko on "ITMS-90338: Non-public API usage". Siitä on kolme versiota sen mukaan, mitä Apple löysi binääristäsi:
- "references non-public selectors": Objective-C-metodien nimiä, kuten
boldFontOfSize:; - "references non-public symbols": funktioita, joiden edessä on alaviiva, kuten
__dyld_get_shared_cache_range; - "contains or inherits from non-public classes": luokan nimi.
Jokainen versio antaa polun ja sen jälkeen listan nimistä. Tekstissä on lisäksi kaksi neuvoa: nimeä metodisi uudelleen, jos niiden nimi on sama kuin yksityisellä rajapinnalla, ja poista staattinen kirjasto, joka sisältää ne. Syyskuun 2026 sähköpostissa ehdotetaan myös xcrun swift-demangle -komentoa koodattujen Swift-nimien muuttamiseksi luettaviksi.
Tarkistuksen taustalla on guideline 2.5.1: sovellus saa käyttää vain julkisia rajapintoja. Apple Developer Programin lisenssisopimus toistaa saman kohdassa 3.3.1: ei kutsuja yksityisiin rajapintoihin. Tämän säännön ihmistarkastus käydään läpi guideline 2.5.1 -oppaassa. Tässä käsitellään lähetysvirhettä.
Kuten muissakin ITMS-virheissä, kukaan ei ole avannut sovellustasi: Apple analysoi binäärin buildin käsittelyn aikana. Apple ei julkaise listaa yksityisistä rajapinnoista: sähköpostisi nimet ovat ainoa luotettava lista.
Polun lukeminen: SDK vai suoritettava tiedosto?
Listaa edeltävä polku kertoo, mistä tiedostosta etsiä.
Frameworks/Name.framework/Name: nimi on mukaan paketoidussa dynaamisessa frameworkissa eli tietyssä SDK:ssa. Solysin buildissa tässä kansiossa on 14 frameworkia: Hermes, React Native, valmiiksi käännettyinä toimitettuja Expo-moduuleja ja kuvakirjasto SDWebImage.- Pelkkä sovelluksesi nimi: nimi on pääsuoritustiedostossa. Expolla siihen kootaan natiivikoodisi ja lähdekoodista käännetyt podit, jotka linkitetään oletuksena staattisesti. Silloin syyllinen voi olla mikä tahansa natiivikirjasto.
Päätöspuu: mainitusta nimestä korjaukseen
Käy rivit läpi järjestyksessä. Ensimmäinen tilanteeseesi sopiva rivi näyttää suunnan.
| Mitä luet | Mistä etsiä | Korjaus |
|---|---|---|
Nimi alkaa $s tai _$s | xcrun swift-demangle | Aloita puu alusta |
| Ei löydy IPA:stasi | grep bundleen | Lähetä build uudelleen |
| Nimi on julkinen iOS:ssä | iOS SDK:n otsaketiedostot | Lähetä build uudelleen |
API_UNAVAILABLE(ios) | iOS SDK:n otsaketiedostot | Päivitä paketti |
Kohteessa Frameworks/X | SDK, joka tarjoaa X:n | Päivitä SDK |
| Selektori, oma sovelluksesi | Podit ja natiivimoduulit | Lisää etuliite tai päivitä |
Symboli _nimi, sovelluksesi | nm -m, sitten podit | Korvaa kutsu |
| Luokka, oma sovelluksesi | Omat luokkasi ja podisi | Lisää luokalle etuliite |
"Lähetä build uudelleen" -rivit viittaavat väärään hälytykseen, jota käsitellään alempana.
Vaihe 1: avaa lähetetty build
Työskentele Applelle oikeasti lähetetyn tiedoston kanssa, älä projektisi. Lataa IPA buildin sivulta osoitteesta expo.dev ja aja Macillasi:
unzip -q MyApp.ipa -d ipa
ls ipa/Payload/MyApp.app/Frameworks
otool -L ipa/Payload/MyApp.app/MyApp | grep PrivateFrameworks
Toinen rivi listaa mukaan paketoidut frameworkit. Kolmas etsii suoraa linkkiä Applen yksityiseen frameworkiin: sen ei pidä tulostaa mitään. Solysissa otool -L ei löydä yhtään yksityistä frameworkia, ei suoritettavasta tiedostosta eikä 14 frameworkista.
Vaihe 2: etsi tiedosto, joka sisältää nimen
Aloita laajasti. Etsi mainittua nimeä ilman alun alaviivoja koko bundlesta:
grep -rl "dyld_get_shared_cache_range" ipa/Payload/MyApp.app
Komento listaa tiedostot, jotka sisältävät tämän tekstin. Tarkenna sitten nimen tyypin mukaan (selektori, symboli, luokka) löydettyyn tiedostoon, jota merkitään tässä Binary:
strings -a Binary | grep -x "boldFontOfSize:"
nm -m Binary | grep "_dyld_get_shared_cache_range"
nm -m Binary | grep '_OBJC_CLASS_$_ClassName'
Käytä selektorille strings-komentoa, älä nm:ää. Solysin React-frameworkissa nm näyttää metodit luokkineen, kuten -[RCTRootView initWithBridge:moduleName:initialProperties:], mutta ei koskaan pelkkää selektoria initWithBridge:. strings löytää sen.
Symbolin kohdalla lue rivin loppu. Solysissa nm -m näyttää esimerkiksi (undefined) external __dyld_get_image_name (from libSystem): binääri kutsuu funktiota sisältämättä sitä, ja libSystem tarjoaa sen. Juuri tämä funktio on julkinen, kuten seuraava vaihe näyttää.
Vaihe 3: tarkista, onko nimi oikeasti yksityinen
iOS SDK:n otsaketiedostot kuvaavat julkiset rajapinnat. Muutaman sekunnin haku kertoo, löytyykö mainittu nimi niistä ja millä alustoilla. Poista symbolista ensin käännöksessä lisätty alaviiva: _SCDynamicStoreCreate muuttuu muotoon SCDynamicStoreCreate.
SDK=$(xcrun --sdk iphoneos --show-sdk-path)
grep -rn "SCDynamicStoreCreate" "$SDK/usr/include" "$SDK"/System/Library/Frameworks/*/Headers
- lokakuuta 2026 iOS SDK 26.2:lla neljä oikeista ITMS-90338-sähköposteista poimittua nimeä antoivat tämän tuloksen:
| Mainittu nimi | iOS SDK:ssa | Tulkinta |
|---|---|---|
| _dyld_get_shared_cache_range | Puuttuu | Yksityinen rajapinta |
| boldFontOfSize: | Puuttuu | Yksityinen tai törmäys |
| SCDynamicStoreCreate | API_UNAVAILABLE(ios) | Vain macOS |
| isMainFrame | WebKitin ominaisuus | Julkinen |
Nimi, joka löytyy ja on saatavilla iOS:ssä, viittaa väärään hälytykseen. Puuttuva nimi viittaa yksityiseen rajapintaan tai nimitörmäykseen. Kaksi rajoitusta: pelkästään Swiftissä julkinen rajapinta ei näy näissä otsaketiedostoissa, ja setDelegate:-tyyppisen aksessorin kohdalla etsi ominaisuutta delegate.
Vaihe 4: jäljitä paketti
Jos polussa mainitaan framework, sen nimi johtaa podiin ja sitä kautta npm-pakettiin:
grep -n "FrameworkName" ios/Podfile.lock
npm explain package-name
npm explain kertoo, mikä riippuvuus asensi paketin, jos et itse lisännyt sitä koskaan.
Jos polussa mainitaan suoritettava tiedosto, etsi nimeä natiivilähteistä ja sitten podeista:
grep -rl --include='*.m' --include='*.mm' --include='*.swift' --include='*.h' \
"boldFontOfSize" node_modules modules
grep -rl "boldFontOfSize" ios/Pods
Muokkaa kansiolistaa tarpeen mukaan: modules on paikallisten Expo-moduulien kansio. ios/Pods-kansio syntyy komennolla npx expo prebuild -p ios, joka asentaa Macilla myös podit. Huomaa: komento voi luoda ios-kansion uudelleen. Jos olet muokannut sitä käsin, työskentele kopion kanssa.
ios/Pods-haku on yhtä tärkeä kuin lähdekoodihaku. Solysissa tässä kansiossa on 15 valmiiksi käännettynä toimitettua frameworkia .xcframework-muodossa: Expo-moduuleja, Hermes, React Native ja kolmannen osapuolen SDK:ita. Pelkkiin lähdetiedostoihin rajattu haku ohittaisi niiden koodin.
Tyypilliset syyt
Kolmannen osapuolen SDK, liian vanha tai liian uusi. Syyskuussa 2026 eräs Flutter-kehittäjä raportoi tietoturva-SDK:n aiheuttamasta hylkäyksestä: sen versio 8.2.3 kutsui funktiota __dyld_get_shared_cache_range. Versio 8.2.2 meni läpi, ja julkaisija neuvoi palaamaan siihen korjausta odotellessa.
Natiivimoduuli, joka kutsuu dokumentoimatonta rajapintaa. Oma moduulisi, plugin tai pieni kirjasto voi käyttää foorumilta löydettyä UIKitin sisäistä metodia. Tarkistus tunnistaa sen nimestä.
Nimitörmäys. Metodillasi tai luokallasi on sattumalta sama nimi kuin Applen yksityisellä rajapinnalla. Viesti ottaa tämän huomioon ja pyytää nimeämään sen uudelleen. Apple suosittelee lisäämään etuliitteen sen luokkiin lisättyihin metodeihin, esimerkiksi kolme pientä kirjainta ja alaviiva.
Rajapinta, joka on julkinen macOS:ssä mutta ei iOS:ssä. Vuonna 2024 .NET MAUI -sovellus hylättiin funktion _SCDynamicStoreCreate takia. Apple kyllä dokumentoi tämän funktion, mutta vain macOS:lle, ja iOS SDK:n otsaketiedosto merkitsee sen API_UNAVAILABLE(ios, tvos, watchos).
Korjaa kiertämättä
- Päivitä riippuvuus. Expon seuraamien pakettien osalta
npx expo install --checkilmoittaa ne, jotka eivät vastaa SDK:tasi, Expo CLI:n dokumentaation mukaan. Muiden kohdalla lue muutosloki. - Palaa edelliseen versioon, jos nimi tuli mukaan uudessa versiossa, ja ilmoita julkaisijalle.
- Korvaa tai poista hylätty kirjasto.
- Nimeä uudelleen metodisi tai luokkasi etuliitteellä.
Älä piilota nimeä. Merkkijonon pilkkominen tai metodin kutsuminen kiertoteitse kätkee käytön korjaamatta sitä. Se on edelleen kielletty säännössä 2.5.1 ja sopimuksessa, ja silloin vaarassa on oma tilisi.
Tee sen jälkeen uusi build uudella build-numerolla. Etäpäivitys ei riitä: nimi on käännetyssä natiivikoodissa. Aja ennen lähetystä vaihe 2 uudelleen uudelle IPA:lle. Nimen ei pidä enää näkyä.
Kun kyse on väärästä hälytyksestä
Applen tarkistus erehtyy joskus. 6. kesäkuuta 2022 React Native- ja Flutter-sovellukset saivat ITMS-90338:n WebKitin julkisista nimistä, kuten setNavigationDelegate: tai isMainFrame, myös lähes muuttamattomissa päivityksissä. Seuraavana päivänä eräs Applen insinööri kirjoitti, että ongelma oli korjattu validoinnin puolella, ja kehotti lähettämään buildit uudelleen. Keskustelu on tallessa Expon GitHub-repossa.
Kolme yhtäaikaista merkkiä viittaa väärään hälytykseen:
- build muistuttaa viimeisintä hyväksyttyä buildia;
- vaihe 2 ei löydä nimeä, tai vaihe 3 näyttää sen olevan julkinen iOS:ssä;
- muut kehittäjät raportoivat saman virheen samana päivänä Applen foorumeilla.
Tarkista silloin Applen palvelujen tila ja lähetä build uudelleen uudella numerolla. Jos virhe jatkuu, kirjoita Applen kehittäjätukeen ja liitä koko sähköposti. Nimitörmäys taas ei Applen silmissä ole väärä hälytys: nimeä uudelleen.
Ennen seuraavaa lähetystäsi
Muillekin ITMS-virheille on oma oppaansa: ITMS-90725 Xcoden versiosta, ITMS-91053 tietosuojamanifestista ja ITMS-90034 allekirjoituksesta. Kun build on hyväksytty, asenna se TestFlightilla ennen tarkastusta.
Reviewerin hylkäykset vaativat enemmän harkintaa: toimintatapa on sivulla Apple hylkäsi sovelluksen, ja yleisimmät syyt löydät artikkelista miksi Apple hylkää sovelluksen.
Jos haluat tarkistaa kokonaisuuden ennen lähetystä, Review Kit sisältää tarkistuslistani ja Claude Code -skillejä, jotka käyvät projektisi läpi. Jos lähetyksesi jumittaa ja haluat ihmisen näkemyksen, varaa tunti kanssani: käydään projektisi läpi videopuhelussa sinun näytölläsi. Ja jos valmistelet ensimmäistä julkaisuasi, tee ilmainen diagnoosi: se laittaa vaiheet järjestykseen ja lähettää sinulle tarkistuslistani Applen hylkäysten välttämiseen.
Usein kysytyt kysymykset
Onko ITMS-90338 App Review -hylkäys?
Ei. Se on automaattinen tarkistus buildin käsittelyn aikana, ennen mitään ihmistarkastusta. Hylätty build ei päädy TestFlightiin eikä tarkastukseen. Jos reviewer myöhemmin huomaa yksityisen rajapinnan, se kuuluu guideline 2.5.1:n piiriin.
Voiko ITMS-90338:n korjata etäpäivityksellä?
Ei. Mainitut nimet ovat binäärin käännetyssä natiivikoodissa. Etäpäivitys muuttaa vain JavaScriptiä ja resursseja. Korjaa riippuvuus, tee uusi build ja lähetä se.
Miksi Apple mainitsee metodeja, joita en ole koskaan kirjoittanut?
Koska ne tulevat mukaan paketoidusta kirjastosta tai nimitörmäyksestä: jokin riippuvuus määrittelee metodin, jolla on sama nimi kuin yksityisellä rajapinnalla. Apple lukee binäärissä olevat nimet, ei lähdekoodiasi. Jäljitä paketti komennoilla grep ja npm explain.
Mistä tiedän, onko rajapinta julkinen iOS:ssä?
Etsi sen nimeä iOS SDK:n otsaketiedostoista, joiden polun xcrun --sdk iphoneos --show-sdk-path kertoo, ja lue sen saatavuus. Applen dokumentaatiosivu kertoo sen myös. Vain macOS:lle dokumentoitu funktio ei ole julkinen iPhonessa.
Pitääkö build-numeroa vaihtaa korjauksen jälkeen?
Kyllä. Anna EAS:n kasvattaa sitä: samalle versiolle jo lähetetty numero voidaan hylätä virheellä ITMS-90189.

