"Uygulamanız 200MB'ı aştığı için cellular download yapılamıyor." Bu mesajı gördüğün an, kullanıcıların yarısını kaybettin demektir.
App size, kullanıcı ediniminde kritik bir faktör. Araştırmalar gösteriyor ki her 10MB artış, download oranını %2.5 düşürüyor. Bu rehberde, uygulamanı nasıl küçülteceğini öğreneceksin.
İçindekiler
- Neden App Size Önemli?
- App Size Raporu Oluşturma
- Asset Optimization
- Binary Size Azaltma
- App Thinning
- On-Demand Resources
- Dynamic Library Stratejileri
- Build Settings Optimizasyonu
- Continuous Monitoring
- Gerçek Dünya Case Study
- Sonuç ve Öneriler
Neden App Size Önemli?
Apple'ın koyduğu sınırlar:
Limit | Değer | Sonuç |
|---|---|---|
**Cellular Download** | 200 MB | Üstü sadece WiFi |
**App Store Limit** | 4 GB | Upload red |
**Executable Limit** | 500 MB | Her slice için |
**watchOS Limit** | 75 MB | Daha katı |
İstatistikler
- %50: kullanıcı 100MB+ uygulamaları indirmekten kaçınıyor
- %20: kullanıcı WiFi beklemek yerine vazgeçiyor
- Her 10MB azalma = +2.5% conversion rate
⚠️ Dikkat: App Store'da gördüğün boyut, thinned boyut değil!
App Size Raporu Oluşturma
Xcode'un built-in araçlarıyla analiz başla:
Archive ve Export
bash
1# Archive yap2xcodebuild -scheme MyApp -archivePath MyApp.xcarchive archive3 4# Export with app thinning report5xcodebuild -exportArchive \6 -archivePath MyApp.xcarchive \7 -exportPath ./Export \8 -exportOptionsPlist ExportOptions.plistBinary Size Analizi
bash
1# Binary'nin segment dağılımını gör2size -l -m MyApp.app/MyApp3 4# Symbol bilgisi5nm -S MyApp.app/MyApp | sort -k 2 -r | head -50Asset Optimization
Genellikle app size'ın %60-80'i asset'lerden gelir:
Image Compression
bash
1# PNG optimization2pngquant --quality=65-80 --speed 1 --output optimized.png original.png3 4# WebP conversion (iOS 14+)5cwebp -q 80 image.png -o image.webp6 7# JPEG optimization 8jpegoptim --max=80 --strip-all image.jpgAsset Catalog Optimization
Build Settings'de:
- ASSETCATALOG_COMPILER_OPTIMIZATION = space
Asset Catalog'da:
- Sadece gerekli scale'leri ekle (@2x, @3x)
- PDF yerine PNG kullan
- Unused image'ları sil
Vector vs Raster Karar Ağacı
Görsel basit ve tek renk mi?
- EVET → SF Symbol veya PDF kullan
Fotoğraf mı?
- EVET → HEIC/JPEG kullan
- HAYIR → PNG kullan, WebP'ye çevir (iOS 14+)
Binary Size Azaltma
Dead Code Elimination
swift
1// Build Settings2DEAD_CODE_STRIPPING = YES3STRIP_INSTALLED_PRODUCT = YES4 5// Swift-specific6SWIFT_OPTIMIZATION_LEVEL = -Osize // Release için7 8// Link-Time Optimization9LLVM_LTO = YESSymbol Stripping
swift
1// Build Settings2STRIP_STYLE = all // Release için3DEBUG_INFORMATION_FORMAT = dwarf-with-dsymGenerics Specialization
swift
1// ❌ Her generic kullanımı binary'de duplicate oluşturur2func process<T: Numeric>(_ value: T) -> T {3 return value * 24}5 6// ✅ Protocol-based yaklaşım7protocol Processable {8 static func process(_ value: Self) -> Self9}App Thinning
App Thinning, Apple'ın otomatik optimizasyon sistemi:
Slicing
Asset Catalog'da otomatik:
- Sadece hedef cihaza uygun @2x veya @3x
- Sadece hedef architecture (arm64)
- Sadece hedef cihaz özellikleri
Bitcode
swift
1// Build Settings2ENABLE_BITCODE = YESBitcode, App Store'un binary'yi yeniden optimize etmesine izin verir.
On-Demand Resources
Kullanıcının hemen ihtiyaç duymadığı içerikleri sonra indir:
swift
1class LevelManager {2 private var resourceRequest: NSBundleResourceRequest?3 4 func loadLevel(_ levelTag: String) async throws -> LevelData {5 // Önce cache'i kontrol et6 if Bundle.main.preservationPriority(forTag: levelTag) > 0.5 {7 return try loadLocalLevel(levelTag)8 }9 10 // İndir11 let request = NSBundleResourceRequest(tags: [levelTag])12 self.resourceRequest = request13 14 try await request.beginAccessingResources()15 16 let levelData = try loadLocalLevel(levelTag)17 18 // Cache priority ayarla19 Bundle.main.setPreservationPriority(0.8, forTags: [levelTag])20 21 return levelData22 }23 24 func unloadLevel(_ levelTag: String) {25 resourceRequest?.endAccessingResources()26 resourceRequest = nil27 Bundle.main.setPreservationPriority(0.0, forTags: [levelTag])28 }29}Dynamic Library Stratejileri
Static vs Dynamic
Özellik | Static | Dynamic |
|---|---|---|
**Load Time** | Daha uzun app launch | Lazy load edilebilir |
**Binary Size** | Tek binary, daha büyük | Ayrı .dylib dosyaları |
**Update** | Tüm app güncellenmeli | Sadece library güncellenebilir |
CocoaPods / SPM Optimization
ruby
1# Podfile2use_frameworks! :linkage => :static # Static linkingBuild Settings Optimizasyonu
Release Build Settings
swift
1// Optimization2SWIFT_OPTIMIZATION_LEVEL = -Osize3GCC_OPTIMIZATION_LEVEL = s4 5// Dead Code6DEAD_CODE_STRIPPING = YES7STRIP_INSTALLED_PRODUCT = YES8STRIP_STYLE = all9COPY_PHASE_STRIP = YES10 11// Link-Time Optimization12LLVM_LTO = YES13 14// Bitcode15ENABLE_BITCODE = YES16 17// Asset Optimization18ASSETCATALOG_COMPILER_OPTIMIZATION = space19 20// Swift21SWIFT_COMPILATION_MODE = wholemoduleContinuous Monitoring
Size regression'ları erken yakala:
yaml
1# CI/CD size check2- name: Check Size Limit3 run: |4 SIZE=$(stat -f%z Export/MyApp.ipa)5 MAX_SIZE=200000000 # 200 MB6 if [ $SIZE -gt $MAX_SIZE ]; then7 echo "App size exceeds limit!"8 exit 19 fiGerçek Dünya Case Study
Bir e-ticaret uygulamasını 180MB'dan 65MB'a nasıl düşürdük:
Başlangıç Durumu
- Total: 180 MB
- Assets: 120 MB (67%)
- Binary: 45 MB (25%)
- Other: 15 MB (8%)
Uygulanan Optimizasyonlar
Optimizasyon | Kazanç |
|---|---|
WebP'ye geçiş | -40 MB |
Unused asset temizliği | -25 MB |
On-demand videos | -15 MB |
System fonts kullanımı | -8 MB |
LTO etkinleştirme | -5 MB |
Dead code stripping | -12 MB |
Static linking | -8 MB |
Unused frameworks | -2 MB |
Son Durum
- Total: 65 MB (%64 azalma!)
Easter Egg
Gizli bir bilgi buldun!
Bu bölümde gizli bir bilgi var. Keşfetmek ister misin?
Okuyucu Ödülü
Tebrikler! Bu yazıyı sonuna kadar okuduğun için sana özel bir hediyem var:
ALTIN İPUCU
Bu yazının en değerli bilgisi
Bu ipucu, yazının en önemli çıkarımını içeriyor.
Swift Package Manager Size Impact Analizi
SPM bağımlılıkları binary size'ı ciddi şekilde şişirebilir. Her package'ın etkisini ölçmek kritik önem taşır.
Package Size Ölçüm Script'i
bash
1# Her SPM dependency'nin binary'ye etkisini ölç2# 1. Tüm bağımlılıklar dahil build3xcodebuild -scheme MyApp -configuration Release build4FULL_SIZE=$(stat -f%z Build/Products/Release-iphoneos/MyApp.app/MyApp)5 6# 2. Şüpheli paketi kaldır, tekrar build et7# Package.swift'ten paketi comment'le8xcodebuild -scheme MyApp -configuration Release clean build9REDUCED_SIZE=$(stat -f%z Build/Products/Release-iphoneos/MyApp.app/MyApp)10 11# 3. Farkı hesapla12echo "Package impact: $(( (FULL_SIZE - REDUCED_SIZE) / 1024 )) KB"Popüler Kütüphanelerin Size Impact'i
Kütüphane | Yaklaşık Binary Etkisi | Alternatif | Alternatif Etkisi |
|---|---|---|---|
**Alamofire** | ~1.2 MB | URLSession wrapper | ~50 KB |
**Kingfisher** | ~800 KB | SDWebImage (lighter) | ~500 KB |
**SnapKit** | ~300 KB | NSLayoutConstraint ext | ~20 KB |
**SwiftyJSON** | ~200 KB | Codable (native) | 0 KB |
**Realm** | ~8 MB | Core Data / SwiftData | 0 KB (system) |
**Firebase Analytics** | ~3.5 MB | Custom analytics | ~100 KB |
**Lottie** | ~1.5 MB | Core Animation | 0 KB (system) |
Lightweight Alternatif Stratejisi
swift
1// ❌ Alamofire (1.2 MB binary impact) - basit API call'lar için overkill2import Alamofire3AF.request("https://api.example.com/data").responseDecodable(of: MyModel.self) { response in4 // ...5}6 7// ✅ Native URLSession extension (50 KB) - aynı iş, minimal overhead8extension URLSession {9 func decode<T: Decodable>(10 _ type: T.Type,11 from url: URL12 ) async throws -> T {13 let (data, response) = try await self.data(from: url)14 guard let httpResponse = response as? HTTPURLResponse,15 (200...299).contains(httpResponse.statusCode) else {16 throw URLError(.badServerResponse)17 }18 return try JSONDecoder().decode(T.self, from: data)19 }20}21 22// Kullanım23let data = try await URLSession.shared.decode(MyModel.self, from: apiURL)Image Format Karşılaştırma ve Seçim Rehberi
Doğru image format seçimi, asset boyutunu %50-70 azaltabilir.
Format Benchmark Sonuçları
Format | 1000x1000px Fotoğraf | 1000x1000px Illustration | Transparency | iOS Desteği |
|---|---|---|---|---|
**PNG** | 2.1 MB | 450 KB | Evet | iOS 2+ |
**JPEG (q80)** | 180 KB | 120 KB | Hayır | iOS 2+ |
**WebP (q80)** | 130 KB | 85 KB | Evet | iOS 14+ |
**HEIC (q80)** | 110 KB | 90 KB | Evet | iOS 11+ |
**AVIF** | 95 KB | 70 KB | Evet | iOS 16+ |
Otomatik Asset Dönüştürme Script'i
bash
1#!/bin/bash2# Tüm PNG asset'leri WebP'ye toplu dönüştür3ASSET_DIR="./Assets.xcassets"4SAVINGS=05 6find "$ASSET_DIR" -name "*.png" -type f | while read file; do7 PNG_SIZE=$(stat -f%z "$file")8 WEBP_FILE="$(echo "$file" | sed 's/.png$//').webp"9 10 cwebp -q 80 -m 6 "$file" -o "$WEBP_FILE" 2>/dev/null11 WEBP_SIZE=$(stat -f%z "$WEBP_FILE")12 13 SAVED=$(( (PNG_SIZE - WEBP_SIZE) / 1024 ))14 echo "$(basename "$file"): $SAVED KB saved"15 SAVINGS=$(( SAVINGS + SAVED ))16done17 18echo "Toplam tasarruf: $SAVINGS KB"Karar Matrisi
Fotoğraf veya gerçekçi görsel mi?
- iOS 16+ hedefliyorsan → AVIF
- iOS 14+ hedefliyorsan → WebP
- iOS 11+ hedefliyorsan → HEIC
- Eski iOS desteği → JPEG
Icon veya basit illustration mu?
- Tek renk, vektörel → SF Symbol (0 KB ek maliyet)
- Çok renkli, küçük → WebP veya PNG (asset catalog optimize eder)
- Animasyonlu → Lottie yerine APNG veya Core Animation
Sonuç ve Öneriler
App size optimization sürekli bir süreç. İşte yol haritası:
- Ölç - Mevcut durumu analiz et
- Önceliklendir - En büyük kazancı verecek alanları belirle
- Uygula - Bir seferde bir optimizasyon
- Doğrula - Her adımda boyutu kontrol et
- Otomatize - CI/CD'ye entegre et
Kaynaklar
- Apple Developer:: [Doing basic optimization to reduce your app's size](https://developer.apple.com/documentation/xcode/doing-basic-optimization-to-reduce-your-app-s-size)
- Apple Developer:: [On-Demand Resources Guide](https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/On_Demand_Resources_Guide/)
- WWDC 2022:: [Improve app size and runtime performance](https://developer.apple.com/videos/play/wwdc2022/110363/)
*Her byte önemli. Kullanıcıların WiFi beklemesine gerek yok.* 📦

