Dentii’nin v3.0 release’inde build size 150MB’a ulaşmıştı. App Store Connect’te upload 10 dakika sürüyordu. Kullanıcılar “uygulama büyük, cellular’da indiremiyorum” şikayeti yazıyordu. Küçük bir dental tracker uygulaması için bu absurt bir boyuttu.
2 haftada 150MB’tan 40MB’a indirdim. Bu yazıda hangi teknikleri uyguladığımı anlatacağım.
Baseline: ne kadar büyük?
Xcode’da Product > Archive > Export IPA sonrası .ipa file’ın size’ı kontrol et. iOS installed size genelde biraz daha büyük (compressed olduğu için ipa).
Daha detaylı breakdown için Xcode’un App Thinning Report’u (Archive sonrası). Her device için install size görünüyor.
Dentii v3.0:
– .ipa file: 92MB
– App Store install (iPhone 15): 145MB
– iPad install: 158MB
Bu baseline’la optimization’a başladım.
Asset audit (en büyük kazanım)
App binary’nin en büyük kısmı genelde resources: görseller, font’lar, sesler, video’lar.
Xcode’da ilk attığım adım: all assets.xcassets contents’ini analyze etmek.
Dentii’de tespit:
– 3x scaled image’lar hepsinde var. iPhone SE 2x, iPhone 12+ 3x. Ama build her device için tümünü içeriyordu. App Thinning bunu handle ediyor ama asset catalog’da kötü setup vardı.
– Legacy PNG’ler. SF Symbols geldikten sonra gerekli değil ama kod’da hâlâ custom PNG icon’lar vardı.
– Onboarding video’ları. 3 adet onboarding video, her biri 10-15MB. Toplam 45MB.
– Custom illustrations. Designer’ın yüksek resolution PNG olarak attığı. 20+ tane.
Aksiyon:
– SF Symbols’a geç. 40+ custom icon yerine native symbols. Size’dan 5MB tasarruf.
– Onboarding video’ları embed etme. CloudKit’ten stream. App binary 45MB küçüldü.
– Illustrations SVG’ye çevir. SF Symbols API ile vektör. PNG’ye göre %80 küçük.
– Image compression. Tüm kalan PNG’leri ImageOptim ile optimize. %30 kazanım.
Asset optimizasyonu toplam 65MB kazandırdı.
Font audit
Custom font’lar binary’e ekleniyor.
Dentii’de:
– System fonts (Apple provides free)
– Display font için custom TTF (3 weight)
– Fallback monospace font
Her font 500KB-2MB. Bütün weight’leri yüklemek 5-6MB ekliyor.
Aksiyon:
– Kullanmadığım weight’leri sil. 3 weight’ten sadece 2’sini tutuyordum zaten.
– Variable font’a geç. Tek bir file ile tüm weight’ler. %60 küçük.
– Monospace font’u kaldır. .monospaced() SF font’u kullandım.
5MB kazanım.
Third-party SDK audit
Tüm SDK’ları listeleyip her birinin ne kadar size eklediğini check ettim.
Xcode’da Product > Archive > Report Navigator > Archive > Size Report. Binary section’ı her framework’ün size’ını gösteriyor.
Dentii:
– Firebase SDK: 12MB (analytics, crashlytics, messaging, remote config)
– Intercom SDK: 8MB (chat + help center)
– Charts library: 3MB (DGCharts)
– Cryptography library: 4MB (custom encryption)
– Analytics (Mixpanel): 2MB
Toplam third-party: 29MB.
Aksiyon:
– Firebase minimize et. Remote Config ve Messaging’i bırakmadım, Analytics’i Mixpanel ile replace ettim. 8MB tasarruf.
– Intercom’u eval et. Chat feature’ı yaygın kullanılmıyordu, call support’a geçirdik (in-app email). 8MB tasarruf.
– Custom encryption library yerine CryptoKit (native). iOS 13+’a zaten CryptoKit geldi. 4MB tasarruf.
– Charts library’yi özel chart kod’uyla değiştir. Sadece 3 chart type kullanıyorduk, SwiftUI Path primitive’leriyle yazmak 2 günlük iş. 3MB tasarruf.
Third-party reduction: 23MB.
Swift compiler optimization
Compile ayarları size etkiliyor:
SWIFT_COMPILATION_MODE = wholemodule (release için). Cross-file optimization yapıyor, binary küçülüyor.
SWIFT_OPTIMIZATION_LEVEL = -O (release için). Default -Osize yerine -O ile balance.
Yerine -Osize kullanabilirsin: smaller binary, slightly slower. Benim için -O optimal.
ENABLE_BITCODE = NO. iOS 16+ deprecated, zaten kapatman gerekiyor. Bitcode eskiden size’ı artırıyordu.
Strip debug symbols from binary. Release build’te debug symbols app binary’ye gömülüyor. Project settings > “Strip Debug Symbols During Copy” = YES.
DWARF with dSYM file. Debug symbols separate file’da. Crash reporter için dSYM upload et, app binary’de olmasın.
Bu compiler setting’leri 2-3MB kazandırdı.
Dynamic frameworks vs static
Dynamic framework’ler file system’de ayrı ayrı yer kaplıyor. Static library’ye çevirirsen binary’ye dahil, overall size düşüyor (bazen).
Benim deneyime göre: çoğu case’te fark önemsiz. Linking time biraz değişiyor. Benchmark yapmadan switch etme.
Localization strings
36 dile lokalize bir app’in strings file’ları 10+MB olabiliyor.
Aksiyon: *.xcstrings format kullan, Apple strings’i compile edip app’e embed ediyor. TXT file’lara göre %50 daha küçük.
1-2MB kazanım.
Asset catalog optimization
Asset catalog’daki image’ların compression ayarı:
- JPEG: photographs için. %20-30 smaller than PNG.
- HEIC: iOS 11+ için. JPEG’den daha efficient.
- PNG-24 vs PNG-8: PNG-8 indexed color, çok smaller if color palette limited.
Xcode’da her image’ın properties’inde preserve vector data, preserve color depth ayarları var. Gereksiz olanı kapat.
App Thinning
App Thinning Apple’ın automatic size optimization’ı. Her user sadece kendi device’ına özel olan assets’i indiriyor.
3 component:
1. App Slicing: iPhone SE sadece 2x image’ları alıyor. iPhone 15 3x. iPad ayrı set.
2. On-Demand Resources: Rare-used asset’ler install’da değil, kullanıldığında indiriliyor. Dentii’nin onboarding video’ları için bunu kullandım.
3. Bitcode: iOS 16’dan sonra deprecated. Ignore.
App Thinning activated olduğunda kullanıcı’nın indirme size’ı total binary size’dan küçük oluyor. iPhone 15 user’ı app thinning sayesinde 45MB indirdi (asset 3x only, iPad assets’i yok).
On-Demand Resources (ODR)
Initial install’a dahil olmayan asset’ler. Tag’lı olarak işaretleniyor, ilk kullanıldığında download.
Kullanım:
// Asset catalog'da asset'e tag ekle: "onboarding"
// Kod'da request et
let request = NSBundleResourceRequest(tags: ["onboarding"])
request.beginAccessingResources { error in
if error == nil {
// Asset'e erişim hazır
}
}Dentii’de onboarding video’larını ODR yaptım. Initial download’da yoklar, kullanıcı onboarding’i başlatınca 20-30 saniye’de indiriliyor.
Final numbers
150MB → 40MB recovery:
| Optimization | Size Saved |
|————–|————|
| SF Symbols migration | 5MB |
| Onboarding video streaming | 45MB |
| Illustration SVG convert | 10MB |
| Font optimization | 5MB |
| Firebase reduction | 8MB |
| Intercom removal | 8MB |
| CryptoKit native | 4MB |
| Custom chart code | 3MB |
| Compiler optimizations | 3MB |
| Asset compression | 10MB |
| Strings catalog migration | 2MB |
| App Thinning + ODR | 7MB |
| Total | 110MB |
Result: 40MB binary, 3-day implementation after investigation, zero functionality lost.
Process: how to find bloat
Next time’a nasıl approach ederim:
- Archive et, .ipa file size ölç. Baseline.
- Xcode’da Size Report review et. Her component’in ne kadar size aldığını gör.
- Top 3 bloat source’u belirle. Genelde: assets, third-party, fonts.
- Her biri için action plan yaz. Hangi asset’ler kalkabilir, hangi SDK minimize edilebilir.
- Prioritize by impact vs effort. SDK removal high-impact, high-effort. Asset audit low-effort high-impact.
- Implement, re-measure. Her optimization’dan sonra archive, size compare.
This cycle 2-3 hafta içinde ciddi reduction veriyor.
App Store penalty for large apps?
App Store cellular download limit 200MB (2024’te 500MB’a çıktı). Bu limit’in altında olması kritik.
Ama psychological limit daha önemli. 100MB üstü app için kullanıcı tereddüt ediyor. 50MB altında hızlıca indiriyor.
40-50MB target her yeni release için.
Sonuç
App binary size actively managed olması gereken bir dimension. Her release’de size regresyonu olmamalı. 2 haftada 110MB düşürdüm, 3 yıldır korudum 40-50MB range.
Asset audit, third-party SDK minimize, SF Symbols native, font optimization, ODR. Bu 5 teknik çoğu app’te %50+ size reduction veriyor.
Yeni app kurarken size’ı baştan düşün. ‘Sonra optimize ederim’ demekten önce disiplinli baştan kurmak daha kolay.