ITMS-90338 hatası: Expo'da “Non-public API usage” çözümü
Yazan: Mehdi Azizi
tarihinde yayınlandı, 9 dk.
ITMS-90338: build'in Apple'ın özel saydığı bir metodu, fonksiyonu ya da sınıfı içeriyor. Sorumlu bağımlılığı bul, güncelle ve yeniden build al.
ITMS-90338, Apple'ın build'in üzerinde yaptığı otomatik bir kontrol. Binary'nin Apple'ın özel (private) saydığı API'lere başvurduğunu söylüyor: Objective-C metotları, fonksiyonlar ya da sınıflar. Çözüm: e-postada geçen dosyayı bul, ismi içeren bağımlılığa kadar geri git, onu güncelle ya da kendi metodunun adını değiştir, sonra yeniden build al.
Expo'da bu isim neredeyse her zaman native bir kütüphaneden gelir, JavaScript'inden nadiren. 15 Ekim 2026'da bu rehberdeki analiz komutlarını, mini oyunlu alarm uygulamam Solys'in (Expo SDK 57) simülatör build'i ve Xcode 26.2'nin iOS SDK'sı üzerinde çalıştırdım. E-postayı nasıl okuyacağını, suçluyu nasıl bulacağını ve yanlış alarmı nasıl tanıyacağını anlatıyorum.
ITMS-90338 hatası ne anlama geliyor?
Mesajın başlığı "ITMS-90338: Non-public API usage". Apple'ın binary'nde ne bulduğuna göre üç çeşidi var:
- "references non-public selectors":
boldFontOfSize:gibi Objective-C metot isimleri; - "references non-public symbols": başında alt çizgi olan fonksiyonlar, örneğin
__dyld_get_shared_cache_range; - "contains or inherits from non-public classes": bir sınıf adı.
Her çeşit önce bir yol, sonra isim listesini verir. Metin iki tavsiye de ekler: isimleri özel bir API ile çakışıyorsa metotlarının adını değiştirmek ve onları içeren statik kütüphaneyi kaldırmak. Eylül 2026 tarihli bir e-posta ayrıca kodlanmış Swift isimlerini okunur hale getirmek için xcrun swift-demangle öneriyor.
Bu kontrolün arkasındaki kural guideline 2.5.1: bir uygulama yalnızca public API'leri kullanabilir. Apple Developer Program lisans sözleşmesi de 3.3.1 maddesinde bunu tekrarlar: özel API çağrısı yok. Bu kuralın insan incelemesi guideline 2.5.1 rehberinde detaylı anlatılıyor. Burada gönderim hatasını ele alıyoruz.
Diğer ITMS hataları gibi, uygulamanı kimse açmadı: Apple binary'yi build işlenirken analiz etti. Apple özel API'lerin listesini yayınlamıyor: e-postandaki isimler tek güvenilir liste.
Yolu okumak: bir SDK mı, senin executable'ın mı?
Listeden önce yazan yol, hangi dosyada arayacağını söyler.
Frameworks/Nom.framework/Nom: isim gömülü bir dinamik framework'te, yani belirli bir SDK'da. Solys build'inde bu klasörde 14 framework var: Hermes, React Native, önceden derlenmiş gelen Expo modülleri ve SDWebImage görsel kütüphanesi.- Sadece uygulamanın adı: isim ana executable'da. Expo'da bu dosya senin native kodunu ve kaynaktan derlenen, varsayılan olarak statik bağlanan pod'ları bir araya getirir. Bu durumda herhangi bir native kütüphane sorumlu olabilir.
Karar ağacı: geçen isimden çözüme
Satırları sırayla oku. Durumuna uyan ilk satır sana ipucunu verir.
| Ne okuyorsun | Nerede aranır | Çözüm |
|---|---|---|
$s veya _$s ile isim | xcrun swift-demangle | Ağaca baştan dön |
| IPA'nda bulunamıyor | Bundle üzerinde grep | Yeniden build gönder |
| iOS'ta public isim | iOS SDK header'ları | Yeniden build gönder |
API_UNAVAILABLE(ios) | iOS SDK header'ları | Paketi güncelle |
Frameworks/X içinde | X'i sağlayan SDK | SDK'yı güncelle |
| Selector, senin uygulaman | Pod'lar ve native modüller | Önek ekle ya da güncelle |
_nom sembolü, uygulaman | nm -m, sonra pod'lar | Çağrıyı değiştir |
| Sınıf, senin uygulaman | Senin sınıfların ve pod'ların | Sınıfa önek ekle |
"Yeniden build gönder" satırları yanlış alarmı gösterir, aşağıda ele alıyorum.
Adım 1: gönderilen build'i aç
Projen üzerinde değil, Apple'a gerçekten gönderilen dosya üzerinde çalış. IPA'yı expo.dev'deki build sayfasından indir, sonra Mac'inde çalıştır:
unzip -q MyApp.ipa -d ipa
ls ipa/Payload/MyApp.app/Frameworks
otool -L ipa/Payload/MyApp.app/MyApp | grep PrivateFrameworks
İkinci satır gömülü framework'leri listeler. Üçüncüsü Apple'ın özel bir framework'üne doğrudan bağlantı arar: hiçbir şey göstermemeli. Solys'te otool -L ne executable'da ne de 14 framework'te özel framework buluyor.
Adım 2: ismi içeren dosyayı bul
Geniş başla. Geçen ismi, baştaki alt çizgiler olmadan, tüm bundle'da ara:
grep -rl "dyld_get_shared_cache_range" ipa/Payload/MyApp.app
Komut bu metni içeren dosyaları listeler. Sonra ismin türüne göre (selector, sembol, sınıf) bulunan dosya üzerinde, burada Binaire diye geçiyor, daralt:
strings -a Binaire | grep -x "boldFontOfSize:"
nm -m Binaire | grep "_dyld_get_shared_cache_range"
nm -m Binaire | grep '_OBJC_CLASS_$_NomDeClasse'
Selector için nm değil strings kullan. Solys'in React framework'ünde nm, metotları sınıflarıyla birlikte gösteriyor, örneğin -[RCTRootView initWithBridge:moduleName:initialProperties:], ama initWithBridge: selector'ünü asla tek başına göstermiyor. strings onu buluyor.
Sembol için satırın sonunu oku. Solys'te nm -m örneğin (undefined) external __dyld_get_image_name (from libSystem) gösteriyor: binary fonksiyonu içermeden çağırıyor, onu libSystem sağlıyor. Bu fonksiyon public, bir sonraki adımda göreceğin gibi.
Adım 3: ismin gerçekten özel olup olmadığını kontrol et
iOS SDK header'ları public API'leri tanımlar. Birkaç saniyelik bir arama, geçen ismin orada olup olmadığını ve hangi platformlarda geçerli olduğunu söyler. Sembol için önce derlemede eklenen alt çizgiyi kaldır: _SCDynamicStoreCreate, SCDynamicStoreCreate olur.
SDK=$(xcrun --sdk iphoneos --show-sdk-path)
grep -rn "SCDynamicStoreCreate" "$SDK/usr/include" "$SDK"/System/Library/Frameworks/*/Headers
15 Ekim 2026'da, iOS 26.2 SDK'sı ile, gerçek ITMS-90338 e-postalarından alınan dört isim şu sonucu veriyor:
| Geçen isim | iOS SDK'da | Yorum |
|---|---|---|
| _dyld_get_shared_cache_range | Yok | Özel API |
| boldFontOfSize: | Yok | Özel ya da çakışma |
| SCDynamicStoreCreate | API_UNAVAILABLE(ios) | Sadece macOS |
| isMainFrame | WebKit property'si | Public |
Var olan ve iOS'ta kullanılabilen bir isim yanlış alarma işaret eder. Olmayan bir isim özel bir API'ye ya da çakışmaya işaret eder. İki sınır var: yalnızca Swift'te public olan bir API bu header'larda görünmez, setDelegate: gibi bir erişimci için de delegate property'sini ara.
Adım 4: pakete kadar geri git
Yol bir framework'ten bahsediyorsa, adı seni pod'a, sonra npm paketine götürür:
grep -n "NomDuFramework" ios/Podfile.lock
npm explain nom-du-paquet
Paketi kendin hiç eklemediysen, npm explain onu hangi bağımlılığın kurduğunu söyler.
Yol executable'dan bahsediyorsa, ismi native kaynaklarda, sonra pod'larda ara:
grep -rl --include='*.m' --include='*.mm' --include='*.swift' --include='*.h' \
"boldFontOfSize" node_modules modules
grep -rl "boldFontOfSize" ios/Pods
Klasör listesini kendine göre ayarla: modules, yerel Expo modüllerinin klasörü. ios/Pods klasörü, Mac'te pod'ları da kuran npx expo prebuild -p ios sonrasında ortaya çıkar. Dikkat: bu komut ios klasörünü yeniden oluşturabilir. Klasörü elle değiştirdiysen bir kopya üzerinde çalış.
ios/Pods içindeki arama, kaynaklardaki arama kadar önemli. Solys'te bu klasör .xcframework formatında, önceden derlenmiş gelen 15 framework içeriyor: Expo modülleri, Hermes, React Native ve üçüncü parti SDK'lar. Sadece kaynak dosyalarla sınırlı bir arama onların kodunu kaçırır.
Tipik nedenler
Çok eski ya da çok yeni bir üçüncü parti SDK. Eylül 2026'da bir Flutter geliştiricisi bir güvenlik SDK'sı yüzünden aldığı reddi bildirdi: SDK'nın 8.2.3 sürümü __dyld_get_shared_cache_range çağırıyordu. 8.2.2 sürümü geçiyordu ve geliştirici firma, düzeltme gelene kadar ona geri dönmeyi önerdi.
Belgelenmemiş bir API çağıran native modül. Kendi modülün, bir plugin ya da küçük bir kütüphane, bir forumda bulunmuş UIKit'in dahili bir metodunu kullanıyor olabilir. Kontrol onu isminden yakalar.
İsim çakışması. Metodun ya da sınıfın, tesadüfen, Apple'ın özel bir API'siyle aynı adı taşıyor. Mesaj bunu öngörüyor ve adını değiştirmeni istiyor. Apple, kendi sınıflarına eklenen metotlara önek koymayı öneriyor, örneğin üç küçük harf ve ardından bir alt çizgi.
macOS'ta public olan ama iOS'ta olmayan bir API. 2024'te bir .NET MAUI uygulaması _SCDynamicStoreCreate yüzünden reddedildi. Apple bu fonksiyonu belgeliyor, ama sadece macOS için, iOS SDK header'ı da onu API_UNAVAILABLE(ios, tvos, watchos) olarak işaretliyor.
Hileye başvurmadan düzelt
- Bağımlılığı güncelle. Expo'nun takip ettiği paketler için
npx expo install --check, Expo CLI dokümantasyonuna göre SDK'nla uyuşmayanları gösterir. Diğerleri için sürüm notlarını oku. - Önceki sürüme dön, eğer ismi yeni sürüm getirdiyse, ve geliştiriciyi haberdar et.
- Terk edilmiş bir kütüphaneyi değiştir ya da kaldır.
- Metodunun ya da sınıfının adını bir önekle değiştir.
İsmi gizleme. Bir string'i parçalamak ya da metodu dolambaçlı yoldan çağırmak kullanımı düzeltmez, sadece saklar. Bu yine 2.5.1 kuralı ve sözleşme tarafından yasak, ve o zaman risk altına giren senin hesabın olur.
Sonra yeni bir build numarası ile yeniden build al. Uzaktan güncelleme yetmez: isim derlenmiş native kodun içinde. Göndermeden önce 2. adımı yeni IPA üzerinde tekrar çalıştır. İsim artık görünmemeli.
Yanlış alarm olduğunda
Apple'ın kontrolü bazen yanılıyor. 6 Haziran 2022'de React Native ve Flutter uygulamaları, setNavigationDelegate: ya da isMainFrame gibi WebKit'in public isimleri için ITMS-90338 aldı, neredeyse hiç değişmemiş güncellemelerde bile. Ertesi gün bir Apple mühendisi sorunun doğrulama tarafında çözüldüğünü yazdı ve build'lerin yeniden gönderilmesini istedi. Konu Expo'nun GitHub deposunda duruyor.
Üç ipucu bir aradaysa yanlış alarm olması muhtemel:
- build, kabul edilen son build'e benziyor;
-
- adım ismi bulamıyor ya da 3. adım onu iOS'ta public gösteriyor;
- başka geliştiriciler aynı gün Apple forumlarında aynı hatayı bildiriyor.
Bu durumda Apple servis durumuna bak, sonra yeni bir numarayla yeniden build gönder. Hata devam ederse, e-postanın tamamıyla Apple geliştirici desteğine yaz. İsim çakışması ise Apple'ın gözünde yanlış alarm değil: adını değiştir.
Bir sonraki gönderimden önce
Diğer ITMS hatalarının da rehberi var: Xcode sürümü için ITMS-90725, gizlilik manifestosu için ITMS-91053 ve imza için ITMS-90034. Build kabul edildikten sonra, incelemeden önce onu TestFlight ile kur.
Bir reviewer'ın reddi daha fazla geri çekilip bakmayı gerektirir: izlenecek yol Apple tarafından reddedilen uygulama sayfasında, en sık nedenler de Apple bir uygulamayı neden reddeder yazısında.
Dosyanı göndermeden önce kontrol etmek için Review Kit, kontrol listemi ve projeni inceleyen Claude Code skill'lerini bir araya getiriyor. Gönderimin takıldıysa ve bir insan gözüne ihtiyacın varsa, benimle bir saatlik görüşme ayarla: projeni görüntülü görüşmede, senin ekranında birlikte ele alalım. İlk yayınına hazırlanıyorsan da ücretsiz tanılamanı yap: adımları sıraya koyar ve sana Apple reddine karşı kontrol listemi gönderir.
Sık sorulan sorular
ITMS-90338 bir App Review reddi mi?
Hayır. Herhangi bir insan incelemesinden önce, build işlenirken yapılan otomatik bir kontrol. Reddedilen build ne TestFlight'a ne de incelemeye ulaşır. Bir reviewer'ın daha sonra fark ettiği özel API ise guideline 2.5.1 kapsamına girer.
ITMS-90338 uzaktan güncellemeyle düzeltilebilir mi?
Hayır. Geçen isimler binary'nin derlenmiş native kodunda. Uzaktan güncelleme yalnızca JavaScript'i ve kaynakları değiştirir. Bağımlılığı düzelt, yeniden build al, sonra gönder.
Apple neden hiç yazmadığım metotlardan bahsediyor?
Çünkü gömülü bir kütüphaneden geliyorlar ya da bir çakışma var: bir bağımlılık, özel bir API ile aynı adı taşıyan bir metot tanımlıyor. Apple senin kaynak kodunu değil, binary'deki isimleri okur. grep ve npm explain ile pakete kadar geri git.
Bir API'nin iOS'ta public olup olmadığını nasıl anlarım?
Adını, yolunu xcrun --sdk iphoneos --show-sdk-path komutunun verdiği iOS SDK header'larında ara, sonra hangi platformlarda kullanılabildiğini oku. Apple'ın dokümantasyon sayfası da bunu belirtir. Yalnızca macOS için belgelenmiş bir fonksiyon iPhone'da public değildir.
Düzeltmeden sonra build numarasını değiştirmek gerekir mi?
Evet. Bırak EAS artırsın: aynı sürüm için daha önce gönderilmiş bir numara ITMS-90189 hatasıyla reddedilebilir.

