# ITMS-90338: popravi »Non-public API usage« v Expu

> ITMS-90338: tvoj build omenja metodo, funkcijo ali razred, ki ga Apple šteje za zasebnega. Najdi odvisnost, jo posodobi in naredi nov build.

Izvirna stran: [ITMS-90338: popravi »Non-public API usage« v Expu](https://devoria.fr/sl/blog/itms-90338-non-public-api-usage-expo)
Avtor: [Mehdi Azizi](https://devoria.fr/sl/mehdi-azizi)
Objava: 2026-11-04
Zadnja revizija vsebine: 2026-11-04


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](https://developer.apple.com/app-store/review/guidelines/#2.5.1): aplikacija sme uporabljati samo javne API-je. [Licenčna pogodba Apple Developer Program](https://developer.apple.com/support/terms/apple-developer-program-license-agreement/) 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](https://devoria.fr/sl/blog/guideline-2-5-1-javni-api-sdk-expo). 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:

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

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

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

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

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

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

```bash
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](https://github.com/talsec/Free-RASP-Flutter/issues/236): 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](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/CustomizingExistingClasses/CustomizingExistingClasses.html), 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`](https://github.com/dotnet/runtime/issues/103949). Apple to funkcijo sicer dokumentira, a [samo za macOS](https://developer.apple.com/documentation/systemconfiguration/1437828-scdynamicstorecreate), glava iOS SDK-ja pa jo označi z `API_UNAVAILABLE(ios, tvos, watchos)`.

## Popravi, ne obidi

1. **Posodobi odvisnost.** Za pakete, ki jih spremlja Expo, `npx expo install --check` po [dokumentaciji Expo CLI](https://docs.expo.dev/more/expo-cli/) označi tiste, ki se ne ujemajo s tvojim SDK-jem. Za druge preberi dnevnik sprememb.
2. **Vrni se na prejšnjo različico**, če je ime prinesla nova, in obvesti izdajatelja.
3. **Zamenjaj ali odstrani** opuščeno knjižnico.
4. **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](https://devoria.fr/sl/blog/app-store-connect-build-number-verzija-stevilka-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](https://github.com/expo/expo/issues/17768).

Trije znaki skupaj kažejo na lažni alarm:

- build je podoben zadnjemu sprejetemu buildu;
- 2. 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](https://developer.apple.com/system-status/), nato pošlji build z novo številko. Če napaka ostane, piši [Applovi podpori za razvijalce](https://developer.apple.com/contact/) 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](https://devoria.fr/sl/blog/itms-90725-sdk-version-issue-expo) za različico Xcode, [ITMS-91053](https://devoria.fr/sl/blog/itms-91053-missing-api-declaration-expo) za manifest zasebnosti in [ITMS-90034](https://devoria.fr/sl/blog/itms-90034-missing-invalid-signature) za podpis. Ko je build sprejet, ga pred pregledom namesti prek [TestFlighta](https://devoria.fr/sl/blog/testflight-testiranje-aplikacije-iphone).

Zavrnitve s strani pregledovalca zahtevajo več premisleka: postopek je na strani [aplikacija, ki jo je Apple zavrnil](https://devoria.fr/sl/expertise/apple-zavrnil-aplikacijo), najpogostejši razlogi pa so v članku [zakaj Apple zavrne aplikacijo](https://devoria.fr/sl/blog/apple-zavrnil-aplikacijo-razlogi).

Da pred pošiljanjem preveriš svojo vlogo, [Review Kit](https://devoria.fr/sl/kits/app-review) 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](https://devoria.fr/sl/coaching): projekt pregledava prek videoklica, na tvojem zaslonu. In če pripravljaš prvo objavo, [opravi brezplačno diagnostiko](https://devoria.fr/sl/diagnostic): 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.


## Tvoj projekt

[Review Kit](https://devoria.fr/sl/kits/app-review): Moj kontrolni seznam za pregled v App Store, moje popravljene zavrnitve Applea, seznam za Google Play in trije skilli za Claude Code. 49 €.

[iOS & Android Kit](https://devoria.fr/sl/kits/ios): Ustvari svojo aplikacijo za iPhone in Android s Claude Code: začetna koda mojih aplikacij, pot do trgovin in vsi kompleti. 99 €.

[Diagnoza: kaj te loči od tvoje aplikacije za iPhone](https://devoria.fr/sl/diagnostic): 7 vprašanj, 60 sekund: izveš, kaj te zares ovira pri objavi aplikacije za iPhone, dobiš pot v 4 korakih in komplet, ki ti ustreza.
