# ITMS-90338: fiks «Non-public API usage» med Expo

> ITMS-90338: builden din nevner en metode, funksjon eller klasse Apple anser som privat. Finn avhengigheten, oppdater den og lag en ny build.

Opprinnelig side: [ITMS-90338: fiks «Non-public API usage» med Expo](https://devoria.fr/no/blog/itms-90338-non-public-api-usage-expo)
Forfatter: [Mehdi Azizi](https://devoria.fr/no/mehdi-azizi)
Publisert: 2026-11-04
Innhold sist revidert: 2026-11-04


ITMS-90338 er en automatisk kontroll Apple kjører på builden din. Den sier at binærfilen din refererer til API-er som Apple regner som private: Objective-C-metoder, funksjoner eller klasser. **Løsningen: finn filen som nevnes i e-posten, spor deg tilbake til avhengigheten som inneholder navnet, oppdater den eller gi metoden din nytt navn, og lag så en ny build.**

Med Expo kommer navnet nesten alltid fra et native bibliotek, sjelden fra JavaScript-koden din. 15. oktober 2026 kjørte jeg analysekommandoene i denne guiden på en simulator-build av Solys, vekkerklokken min med minispill (Expo SDK 57), og på iOS-SDK-en i Xcode 26.2. Her ser du hvordan du leser e-posten, finner synderen og kjenner igjen en falsk positiv.

## Hva betyr feilen ITMS-90338?

Meldingen har tittelen «ITMS-90338: Non-public API usage». Den finnes i tre varianter, avhengig av hva Apple fant i binærfilen din:

- **«references non-public selectors»**: navn på Objective-C-metoder, som `boldFontOfSize:`;
- **«references non-public symbols»**: funksjoner, skrevet med understrek foran, som `__dyld_get_shared_cache_range`;
- **«contains or inherits from non-public classes»**: et klassenavn.

Hver variant oppgir en sti og deretter listen over navn. Teksten gir to råd i tillegg: gi metodene dine nytt navn hvis navnet tilsvarer et privat API, og fjern det statiske biblioteket som inneholder dem. En e-post fra september 2026 foreslår også `xcrun swift-demangle` for å gjøre kodede Swift-navn lesbare.

Regelen bak kontrollen er [guideline 2.5.1](https://developer.apple.com/app-store/review/guidelines/#2.5.1): en app kan bare bruke offentlige API-er. [Lisensavtalen for Apple Developer Program](https://developer.apple.com/support/terms/apple-developer-program-license-agreement/) gjentar det i punkt 3.3.1: ingen kall til private API-er. Den manuelle gjennomgangen av denne regelen er beskrevet i guiden om [guideline 2.5.1](https://devoria.fr/no/blog/guideline-2-5-1-offentlige-api-sdk-expo). Her tar vi for oss opplastingsfeilen.

Som med de andre ITMS-feilene har ingen åpnet appen din: Apple analyserte binærfilen mens builden ble behandlet. **Apple publiserer ingen liste over private API-er: navnene i e-posten din er den eneste pålitelige listen.**

## Les stien: en SDK eller den kjørbare filen din?

Stien som står før listen, forteller deg hvilken fil du skal lete i.

- **`Frameworks/Nom.framework/Nom`**: navnet ligger i et innebygd dynamisk framework, altså i en bestemt SDK. I Solys-builden inneholder denne mappen 14 frameworks: Hermes, React Native, Expo-moduler levert ferdig kompilert og bildebiblioteket SDWebImage.
- **Bare navnet på appen din**: navnet ligger i den kjørbare hovedfilen. Med Expo samler den din native kode og podene som er kompilert fra kildekode, statisk lenket som standard. Da kan hvilket som helst native bibliotek være årsaken.

## Beslutningstreet: fra navnet til løsningen

Gå gjennom radene i rekkefølge. Den første som passer med ditt tilfelle, gir sporet.

| Det du ser                | Hvor du leter            | Løsning                         |
| ------------------------- | ------------------------ | ------------------------------- |
| Navn med `$s` eller `_$s` | `xcrun swift-demangle`   | Start treet på nytt             |
| Finnes ikke i IPA-en      | `grep` på bundelen       | Send en ny build                |
| Offentlig navn på iOS     | Headerne i iOS-SDK-en    | Send en ny build                |
| `API_UNAVAILABLE(ios)`    | Headerne i iOS-SDK-en    | Oppdater pakken                 |
| I `Frameworks/X`          | SDK-en som leverer X     | Oppdater SDK-en                 |
| Selektor, appen din       | Pods og native moduler   | Legg til prefiks eller oppdater |
| Symbol `_navn`, appen din | `nm -m`, deretter podene | Erstatt kallet                  |
| Klasse, appen din         | Klassene og podene dine  | Gi klassen et prefiks           |

Radene «Send en ny build» peker mot en falsk positiv, som behandles lenger ned.

## Steg 1: åpne builden du sendte inn

Jobb med filen som faktisk ble sendt til Apple, ikke med prosjektet ditt. Last ned IPA-en fra build-siden på expo.dev, og kjør dette på Macen din:

```bash
unzip -q MonApp.ipa -d ipa
ls ipa/Payload/MonApp.app/Frameworks
otool -L ipa/Payload/MonApp.app/MonApp | grep PrivateFrameworks
```

Den andre linjen lister de innebygde frameworkene. Den tredje leter etter en direkte lenke til et privat Apple-framework: den skal ikke vise noe. På Solys finner `otool -L` ingen private frameworks, verken i den kjørbare filen eller i de 14 frameworkene.

## Steg 2: finn filen som inneholder navnet

Start bredt. Søk etter navnet, uten understrekene i starten, i hele bundelen:

```bash
grep -rl "dyld_get_shared_cache_range" ipa/Payload/MonApp.app
```

Kommandoen lister filene som inneholder teksten. Snevre deretter inn etter type navn (selektor, symbol, klasse) i filen du fant, her kalt `Binaire`:

```bash
strings -a Binaire | grep -x "boldFontOfSize:"
nm -m Binaire | grep "_dyld_get_shared_cache_range"
nm -m Binaire | grep '_OBJC_CLASS_$_NomDeClasse'
```

**For en selektor bruker du `strings`, ikke `nm`.** På React-frameworket i Solys viser `nm` metoder sammen med klassen, som `-[RCTRootView initWithBridge:moduleName:initialProperties:]`, aldri selektoren `initWithBridge:` alene. `strings` finner den.

For et symbol leser du slutten av linjen. På Solys viser `nm -m` for eksempel `(undefined) external __dyld_get_image_name (from libSystem)`: binærfilen kaller funksjonen uten å inneholde den, og libSystem leverer den. Akkurat den funksjonen er offentlig, som neste steg viser.

## Steg 3: sjekk om navnet faktisk er privat

Headerne i iOS-SDK-en beskriver de offentlige API-ene. Et søk på noen sekunder forteller om navnet finnes der, og på hvilke plattformer. For et symbol fjerner du først understreken som legges til ved kompilering: `_SCDynamicStoreCreate` blir `SCDynamicStoreCreate`.

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

15. oktober 2026, med iOS SDK 26.2, ga fire navn hentet fra ekte ITMS-90338-e-poster dette:

| Navn i e-posten               | I iOS-SDK-en         | Tolkning               |
| ----------------------------- | -------------------- | ---------------------- |
| \_dyld_get_shared_cache_range | Mangler              | Privat API             |
| boldFontOfSize:               | Mangler              | Privat eller kollisjon |
| SCDynamicStoreCreate          | API_UNAVAILABLE(ios) | Bare macOS             |
| isMainFrame                   | WebKit-egenskap      | Offentlig              |

**Et navn som finnes og er tilgjengelig på iOS, peker mot en falsk positiv. Et navn som mangler, peker mot et privat API eller en kollisjon.** To begrensninger: et offentlig API som bare finnes i Swift, dukker ikke opp i disse headerne, og for en accessor som `setDelegate:` søker du etter egenskapen `delegate`.

## Steg 4: spor deg tilbake til pakken

Hvis stien nevner et framework, leder navnet deg til poden og deretter til npm-pakken:

```bash
grep -n "NomDuFramework" ios/Podfile.lock
npm explain nom-du-paquet
```

`npm explain` viser hvilken avhengighet som installerte den, hvis du aldri har lagt den til selv.

Hvis stien nevner den kjørbare filen, søker du etter navnet i de native kildene og deretter i podene:

```bash
grep -rl --include='*.m' --include='*.mm' --include='*.swift' --include='*.h' \
  "boldFontOfSize" node_modules modules
grep -rl "boldFontOfSize" ios/Pods
```

Tilpass mappelisten: `modules` er mappen for lokale Expo-moduler. Mappen `ios/Pods` dukker opp etter `npx expo prebuild -p ios`, som også installerer podene på Mac. Pass på: kommandoen kan gjenskape `ios`-mappen. Har du endret den for hånd, jobber du på en kopi.

**Søket i `ios/Pods` er like viktig som søket i kildene.** På Solys inneholder denne mappen 15 frameworks levert ferdig kompilert, i `.xcframework`-format: Expo-moduler, Hermes, React Native og tredjeparts-SDK-er. Et søk som bare ser på kildefiler, ville gått glipp av koden deres.

## Typiske årsaker

**En tredjeparts-SDK som er for gammel eller for ny.** I september 2026 [rapporterte en Flutter-utvikler en avvisning på grunn av en sikkerhets-SDK](https://github.com/talsec/Free-RASP-Flutter/issues/236): versjon 8.2.3 kalte `__dyld_get_shared_cache_range`. Versjon 8.2.2 gikk gjennom, og utgiveren anbefalte å gå tilbake til den i påvente av en rettelse.

**En native modul som kaller et udokumentert API.** Din egen modul, en plugin eller et lite bibliotek kan bruke en intern UIKit-metode funnet på et forum. Kontrollen fanger den opp på navnet.

**En navnekollisjon.** Metoden eller klassen din har tilfeldigvis samme navn som et privat Apple-API. Meldingen tar høyde for dette og ber deg gi den nytt navn. Apple anbefaler å [gi et prefiks til metoder du legger til i klassene deres](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/CustomizingExistingClasses/CustomizingExistingClasses.html), for eksempel tre små bokstaver etterfulgt av en understrek.

**Et API som er offentlig på macOS, men ikke på iOS.** I 2024 ble en .NET MAUI-app [avvist for `_SCDynamicStoreCreate`](https://github.com/dotnet/runtime/issues/103949). Apple dokumenterer denne funksjonen, men [bare for macOS](https://developer.apple.com/documentation/systemconfiguration/1437828-scdynamicstorecreate), og headeren i iOS-SDK-en merker den `API_UNAVAILABLE(ios, tvos, watchos)`.

## Fiks det uten å omgå det

1. **Oppdater avhengigheten.** For pakkene Expo følger med på, viser `npx expo install --check` hvilke som ikke passer med SDK-en din, ifølge [dokumentasjonen for Expo CLI](https://docs.expo.dev/more/expo-cli/). For de andre leser du endringsloggen.
2. **Gå tilbake til forrige versjon** hvis det var den nye som innførte navnet, og si fra til utgiveren.
3. **Erstatt eller fjern** et forlatt bibliotek.
4. **Gi nytt navn** til metoden eller klassen din, med et prefiks.

**Ikke skjul navnet.** Å dele opp en streng eller kalle metoden via en omvei skjuler bruken uten å fikse den. Den er fortsatt forbudt etter regel 2.5.1 og avtalen, og da er det kontoen din som står i fare.

Lag deretter en ny build med et nytt [buildnummer](https://devoria.fr/no/blog/app-store-connect-build-number-versjon-buildnummer). En fjernoppdatering holder ikke: navnet ligger i den kompilerte native koden. Før du sender inn, kjører du steg 2 på nytt på den nye IPA-en. Navnet skal ikke dukke opp lenger.

## Når det er en falsk positiv

Apples kontroll tar av og til feil. 6. juni 2022 fikk React Native- og Flutter-apper ITMS-90338 for offentlige WebKit-navn, som `setNavigationDelegate:` eller `isMainFrame`, også på oppdateringer som nesten ikke var endret. Dagen etter skrev en Apple-ingeniør at problemet var løst på valideringssiden, og ba folk sende buildene på nytt. Tråden er bevart i [Expos GitHub-repo](https://github.com/expo/expo/issues/17768).

Tre tegn til sammen peker mot en falsk positiv:

- builden ligner på den siste godkjente builden;
- steg 2 finner ikke navnet, eller steg 3 viser at det er offentlig på iOS;
- andre utviklere melder om samme feil samme dag på Apples forum.

I så fall sjekker du [statusen for Apples tjenester](https://developer.apple.com/system-status/) og sender en ny build med nytt nummer. Hvis feilen vedvarer, skriver du til [Apples utviklerstøtte](https://developer.apple.com/contact/) med hele e-posten. En navnekollisjon er derimot ikke en falsk positiv i Apples øyne: gi nytt navn.

## Før neste innsending

De andre ITMS-feilene har også sin egen guide: [ITMS-90725](https://devoria.fr/no/blog/itms-90725-sdk-version-issue-expo) for Xcode-versjonen, [ITMS-91053](https://devoria.fr/no/blog/itms-91053-missing-api-declaration-expo) for personvernmanifestet og [ITMS-90034](https://devoria.fr/no/blog/itms-90034-missing-or-invalid-signature-fiks) for signaturen. Når builden er godkjent, installerer du den med [TestFlight](https://devoria.fr/no/blog/testflight-teste-iphone-app-for-innsending) før gjennomgangen.

Avvisninger fra en reviewer krever mer ettertanke: fremgangsmåten står på siden om [app avvist av Apple](https://devoria.fr/no/expertise/app-avvist-av-apple), og de vanligste årsakene finner du i [hvorfor Apple avviser en app](https://devoria.fr/no/blog/avvist-av-apple-hvorfor-appen-blir-avvist).

For å sjekke prosjektet ditt før innsending samler [Review Kit](https://devoria.fr/no/kits/app-review) sjekklisten min og Claude Code-skills som går gjennom prosjektet ditt. Står innsendingen fast og du vil ha et menneskelig blikk på det, [book en time med meg](https://devoria.fr/no/coaching): vi går gjennom prosjektet ditt på video, på skjermen din. Og forbereder du din første lansering, [ta den gratis diagnosen](https://devoria.fr/no/diagnostic): den setter stegene i riktig rekkefølge og sender deg sjekklisten min mot avvisninger fra Apple.

## Ofte stilte spørsmål

### Er ITMS-90338 en avvisning fra App Review?

Nei. Det er en automatisk kontroll som gjøres mens builden behandles, før noen manuell gjennomgang. Den avviste builden kommer verken til TestFlight eller til gjennomgang. Et privat API som en reviewer oppdager senere, hører derimot inn under guideline 2.5.1.

### Kan man fikse ITMS-90338 med en fjernoppdatering?

Nei. Navnene som nevnes, ligger i den kompilerte native koden i binærfilen. En fjernoppdatering endrer bare JavaScript og ressurser. Fiks avhengigheten, lag en ny build og send den inn på nytt.

### Hvorfor nevner Apple metoder jeg aldri har skrevet?

Fordi de kommer fra et innebygd bibliotek, eller fra en kollisjon: en avhengighet deklarerer en metode med samme navn som et privat API. Apple leser navnene som finnes i binærfilen, ikke kildekoden din. Spor deg tilbake til pakken med `grep` og `npm explain`.

### Hvordan vet jeg om et API er offentlig på iOS?

Søk etter navnet i headerne i iOS-SDK-en, der `xcrun --sdk iphoneos --show-sdk-path` gir stien, og les tilgjengeligheten. Apples dokumentasjonsside viser det også. En funksjon som bare er dokumentert for macOS, er ikke offentlig på iPhone.

### Må jeg endre buildnummeret etter rettelsen?

Ja. La EAS øke det: et nummer som allerede er sendt inn for samme versjon, kan bli avvist med ITMS-90189.


## Prosjektet ditt

[Review Kit](https://devoria.fr/no/kits/app-review): Sjekklisten min for App Store-gjennomgang, Apples avslag på appene mine med rettelser, sjekklisten for Google Play og tre Claude Code-skills. 499 kr.

[iOS & Android Kit](https://devoria.fr/no/kits/ios): Lag din iPhone- og Android-app med Claude Code: startkoden fra appene mine, veien helt til butikkene og alle kitene. 999 kr.

[Diagnose: dette står mellom deg og iPhone-appen din](https://devoria.fr/no/diagnostic): 7 spørsmål, 60 sekunder: du får vite hva som egentlig hindrer deg i å publisere iPhone-appen din, veien din i 4 steg og kitet som passer deg.
