# ITMS-90338: Non-public API usage -virheen korjaus Expolla

> ITMS-90338: buildisi viittaa metodiin, funktioon tai luokkaan, jota Apple pitää yksityisenä. Etsi syyllinen riippuvuus, päivitä se ja tee uusi build.

Alkuperäinen sivu: [ITMS-90338: Non-public API usage -virheen korjaus Expolla](https://devoria.fr/fi/blog/itms-90338-non-public-api-usage-expo)
Kirjoittaja: [Mehdi Azizi](https://devoria.fr/fi/mehdi-azizi)
Julkaistu: 2026-11-04
Sisältö tarkistettu viimeksi: 2026-11-04


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](https://developer.apple.com/app-store/review/guidelines/#2.5.1): sovellus saa käyttää vain julkisia rajapintoja. [Apple Developer Programin lisenssisopimus](https://developer.apple.com/support/terms/apple-developer-program-license-agreement/) 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](https://devoria.fr/fi/blog/guideline-2-5-1-julkiset-api-sdk-expo) -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:

```bash
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:

```bash
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`:

```bash
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`.

```bash
SDK=$(xcrun --sdk iphoneos --show-sdk-path)
grep -rn "SCDynamicStoreCreate" "$SDK/usr/include" "$SDK"/System/Library/Frameworks/*/Headers
```

15. 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:

```bash
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:

```bash
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ä](https://github.com/talsec/Free-RASP-Flutter/issues/236): 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](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/CustomizingExistingClasses/CustomizingExistingClasses.html), 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](https://github.com/dotnet/runtime/issues/103949). Apple kyllä dokumentoi tämän funktion, mutta [vain macOS:lle](https://developer.apple.com/documentation/systemconfiguration/1437828-scdynamicstorecreate), ja iOS SDK:n otsaketiedosto merkitsee sen `API_UNAVAILABLE(ios, tvos, watchos)`.

## Korjaa kiertämättä

1. **Päivitä riippuvuus.** Expon seuraamien pakettien osalta `npx expo install --check` ilmoittaa ne, jotka eivät vastaa SDK:tasi, [Expo CLI:n dokumentaation](https://docs.expo.dev/more/expo-cli/) mukaan. Muiden kohdalla lue muutosloki.
2. **Palaa edelliseen versioon**, jos nimi tuli mukaan uudessa versiossa, ja ilmoita julkaisijalle.
3. **Korvaa tai poista** hylätty kirjasto.
4. **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](https://devoria.fr/fi/blog/app-store-connect-build-number-versio-buildinumero). 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](https://github.com/expo/expo/issues/17768).

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](https://developer.apple.com/system-status/) ja lähetä build uudelleen uudella numerolla. Jos virhe jatkuu, kirjoita [Applen kehittäjätukeen](https://developer.apple.com/contact/) 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](https://devoria.fr/fi/blog/itms-90725-sdk-version-issue-expo) Xcoden versiosta, [ITMS-91053](https://devoria.fr/fi/blog/itms-91053-missing-api-declaration-expo) tietosuojamanifestista ja [ITMS-90034](https://devoria.fr/fi/blog/itms-90034-missing-or-invalid-signature-korjaus) allekirjoituksesta. Kun build on hyväksytty, asenna se [TestFlightilla](https://devoria.fr/fi/blog/testflight-testaa-iphone-sovellus-ennen-lahetysta) ennen tarkastusta.

Reviewerin hylkäykset vaativat enemmän harkintaa: toimintatapa on sivulla [Apple hylkäsi sovelluksen](https://devoria.fr/fi/expertise/apple-hylkasi-sovelluksen), ja yleisimmät syyt löydät artikkelista [miksi Apple hylkää sovelluksen](https://devoria.fr/fi/blog/apple-hylkasi-sovelluksen-syyt).

Jos haluat tarkistaa kokonaisuuden ennen lähetystä, [Review Kit](https://devoria.fr/fi/kits/app-review) 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](https://devoria.fr/fi/coaching): käydään projektisi läpi videopuhelussa sinun näytölläsi. Ja jos valmistelet ensimmäistä julkaisuasi, [tee ilmainen diagnoosi](https://devoria.fr/fi/diagnostic): 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.


## Projektisi

[Review Kit](https://devoria.fr/fi/kits/app-review): App Store -tarkastuksen tarkistuslistani, korjatut Applen hylkäykseni, Google Playn lista ja kolme Claude Code -skilliä. 49 €.

[iOS & Android Kit](https://devoria.fr/fi/kits/ios): Tee iPhone- ja Android-sovelluksesi Claude Codella: sovellusteni pohjakoodi, polku kauppoihin asti ja kaikki kitit. 99 €.

[Diagnoosi: mikä erottaa sinut omasta iPhone-sovelluksestasi](https://devoria.fr/fi/diagnostic): 7 kysymystä, 60 sekuntia: tiedät, mikä oikeasti estää sinua julkaisemasta iPhone-sovellustasi, saat 4 vaiheen polkusi ja sinulle sopivan kitin.
