Bölüm 11 — Konu 54: App Size, Obfuscation, Flavor Yönetimi
Dizi · 54/61 Flutter Türkçe Tutorial
- Bölüm 1 — Konu 1: Flutter Nedir, Mimarisi (Widget → Element → RenderObject, Skia/Impeller)
- Bölüm 1 — Konu 2: Ortam Kurulumu (Flutter SDK, Android Studio/VS Code, Emulator/Simulator, DevTools'a İlk Bakış)
- Bölüm 1 — Konu 3: İlk Proje Yapısı (`pubspec.yaml`, `lib/`, Klasör Mimarisi, `flutter create` Anatomisi)
- Bölüm 1 — Konu 4: Hot Reload / Hot Restart Ne Yapıyor, Neden Önemli
- Bölüm 2 — Konu 5: "Her Şey Widget'tır" Felsefesi, Widget Ağacı
- Bölüm 2 — Konu 6: StatelessWidget vs StatefulWidget + `setState()` Derinlemesine (Rebuild Mekanizması)
- Bölüm 2 — Konu 7: Temel Layout — Container, Row, Column, Stack, Padding, Align, Center
- Bölüm 2 — Konu 8: Constraint Sistemi — "Constraints Go Down, Sizes Go Up, Parent Sets Position"
- Bölüm 2 — Konu 9: `Expanded`, `Flexible`, `Spacer`, Intrinsic Widget'lar
- Bölüm 3 — Konu 10: MaterialApp/CupertinoApp, Scaffold, AppBar
- Bölüm 3 — Konu 11: `ListView`, `GridView`, `SingleChildScrollView` (+ Builder Pattern)
- Bölüm 3 — Konu 12: Text, TextStyle, Icon, Image, Asset Yönetimi
- Bölüm 3 — Konu 13: Custom Widget Yazma Prensipleri (Composition Over Inheritance)
- Bölüm 3 — Konu 14: Navigator 1.0 — Push/Pop, Named Routes
- Bölüm 4 — Konu 15: Form, TextField/TextFormField, GlobalKey<FormState>, Validasyon
- Bölüm 4 — Konu 16: Theme Sistemi (ThemeData, ColorScheme)
- Bölüm 4 — Konu 17: Responsive & Adaptive Tasarım (MediaQuery, LayoutBuilder, OrientationBuilder, Breakpoint Stratejileri)
- Bölüm 5 — Konu 18: Future/Async-Await Flutter Bağlamında, FutureBuilder
- Bölüm 5 — Konu 19: `Stream`, `StreamBuilder`
- Bölüm 5 — Konu 20: HTTP İstekleri (`http` / `dio` Paketleri)
- Bölüm 5 — Konu 21: JSON Serialization (Manuel → `json_serializable`/`freezed`)
- Bölüm 5 — Konu 22: Local Storage — `shared_preferences` → `Hive` → `sqflite`/Drift
- Bölüm 6 — Konu 23: InheritedWidget ve InheritedModel — "Neden setState Yetmiyor" Sorusunun Cevabı
- Bölüm 6 — Konu 24: Provider Paketi
- Bölüm 6 — Konu 25: Riverpod (Modern Yaklaşım, Provider'ın Halefi)
- Bölüm 6 — Konu 26: BLoC/Cubit Pattern (`flutter_bloc`)
- Bölüm 6 — Konu 27: GetX (Tartışmalı Ama Yaygın)
- Bölüm 6 — Konu 28: Karşılaştırma — Hangi Projede Hangisi?
- Bölüm 7 — Konu 29: Navigator 2.0 (Router, RouteInformationParser, RouterDelegate)
- Bölüm 7 — Konu 30: `go_router` Paketi (Pratik ve Modern Çözüm)
- Bölüm 7 — Konu 31: Deep Linking
- Bölüm 7 — Konu 32: Repository Pattern, Katmanlı Mimari (Data/Domain/Presentation)
- Bölüm 7 — Konu 33: Dependency Injection (`get_it`, `injectable`)
- Bölüm 7 — Konu 34: Clean Architecture Uyarlaması, SOLID Prensipleri
- Bölüm 8 — Konu 35: Implicit Animasyonlar
- Bölüm 8 — Konu 36: Explicit Animasyonlar (`AnimationController`, `Tween`, `Curve`)
- Bölüm 8 — Konu 37: Hero Animasyonları
- Bölüm 8 — Konu 38: `CustomPainter` / `Canvas`
- Bölüm 8 — Konu 39: Rive / Lottie Entegrasyonu
- Bölüm 9 — Konu 40: Platform Channels
- Bölüm 9 — Konu 41: Permission Yönetimi (`permission_handler`)
- Bölüm 9 — Konu 42: Kamera, Konum, Sensörler
- Bölüm 9 — Konu 43: Push Notification (Firebase Cloud Messaging)
- Bölüm 9 — Konu 44: Android/iOS Build Sistemleri
- Bölüm 10 — Konu 45: Test Yazımı (Unit, Widget, Integration, Golden)
- Bölüm 10 — Konu 46: CI/CD
- Bölüm 10 — Konu 47: Rebuild Optimizasyonu (`const`, `key` Kullanımı)
- Bölüm 10 — Konu 48: DevTools Profiling
- Bölüm 10 — Konu 49: Lazy Loading, Pagination, Büyük Liste Performansı
- Bölüm 11 — Konu 50: Firebase Ekosistemi (Auth, Firestore, Storage, Functions)
- Bölüm 11 — Konu 51: Supabase Alternatifi
- Bölüm 11 — Konu 52: GraphQL (Opsiyonel)
- Bölüm 11 — Konu 53: Store Yayınlama Süreci (İmzalama, Listing, Versiyonlama)
- Bölüm 11 — Konu 54: App Size, Obfuscation, Flavor Yönetimi
- Bölüm 12 — Konu 55: Flutter Web / Desktop
- Bölüm 12 — Konu 56: Custom `RenderObject` Yazımı
- Bölüm 12 — Konu 57: Engine Mimarisi Derinlemesine (Impeller vs Skia)
- Bölüm 12 — Konu 58: Plugin Geliştirme, pub.dev'e Paket Yayınlama
- Bölüm 12 — Konu 59: Monorepo Mimarisi (Melos)
- Bölüm 12 — Konu 60: Erişilebilirlik (Accessibility) Derinlemesine
- Bölüm 12 — Konu 61: Yerelleştirme (Localization / i18n)
İçindekiler 17 başlık
- App Size — Uygulama Boyutunu Küçültme
- Neden Önemli?
- --analyze-size — Neyin Yer Kapladığını Görmek
- --split-per-abi — Mimariye Özel APK'lar
- İkon/Font Tree-Shaking — Otomatik Bir Kolaylık
- Obfuscation (Kod Gizleme)
- Neden Gerekli?
- Flavor Yönetimi — Aynı Kod Tabanından Birden Fazla Sürüm
- Sorunu Tanımlayalım
- Android Tarafı — build.gradle
- Dart Tarafı — Ortama Özel Giriş Noktaları
- iOS Tarafı — Xcode Schemes
- flutter_flavorizr — Kurulumu Otomatikleştiren Bir Paket
- Bölüm 11'i Kapatırken — Yayınlama Sürecinin Tam Resmi
- 🎯 Bu Dersten Çıkarılması Gerekenler
- 📝 Ödevler
- 🎮 Mini Uygulama — Bölüm 11 Checkpoint: Yayına Hazır Uygulama
Bölüm 11'in son konusu. Bu derste üç farklı ama hepsi yayınlama sürecinin "son rötuşları" sayılabilecek konuyu ele alıyoruz: uygulamanın boyutunu küçültmek, kodunu korumak, ve birden fazla sürümünü (geliştirme/test/üretim) aynı kod tabanından yönetmek.
App Size — Uygulama Boyutunu Küçültme
Neden Önemli?
Büyük bir uygulama, daha uzun indirme süresi, daha fazla depolama kullanımı demektir — özellikle düşük bant genişliği olan pazarlarda (gelişmekte olan ülkeler gibi), uygulamanın boyutu doğrudan indirme oranını etkiler.
--analyze-size — Neyin Yer Kapladığını Görmek
flutter build apk --analyze-sizeBu komut, build sonunda hangi paketin/varlığın uygulamanın ne kadarını oluşturduğunu gösteren bir rapor üretir (DevTools'un App Size aracıyla açılabilir bir dosya olarak). Bölüm 10 Konu 48'de öğrendiğimiz "tahmin etme, ölç" prensibinin burada da geçerli olduğunu görüyorsun — hangi paketin gerçekten büyük olduğunu bilmeden optimize etmeye çalışmak, zaman kaybıdır.
--split-per-abi — Mimariye Özel APK'lar
flutter build apk --split-per-abiAndroid cihazlar, farklı işlemci mimarilerinde (ARM, ARM64, x86) çalışır — normal bir .apk, hepsini birden içerir (kullanmayacağın mimarilerin kodu da dahil). --split-per-abi, her mimari için ayrı bir APK üretir — her kullanıcı, sadece kendi cihazına uygun olanı indirir, bu da belirgin bir boyut azalması sağlar.
Önemli hatırlatma: Konu 53'te öğrendiğimiz Play App Signing ve .aab formatı, aslında bu sorunu zaten büyük ölçüde çözüyor — Play Store, .aab'den, her cihaza özel optimize edilmiş bir APK kendisi üretiyor. --split-per-abi, daha çok Play Store dışı dağıtım (elle .apk paylaşma) senaryolarında değerlidir.
İkon/Font Tree-Shaking — Otomatik Bir Kolaylık
flutter build apk --release
# Çıktıda göreceğin satır:
# Font asset "MaterialIcons-Regular.otf" was tree-shaken, reducing it from 1.6MB to 12KBDart Bölüm 13'te öğrendiğimiz tree-shaking (kullanılmayan kodun derlemeden çıkarılması) kavramı, sadece koda değil, Icons. ile kullandığın ikon fontuna da uygulanır — Flutter, projende hangi ikonları kullandığını analiz eder ve sadece onları içeren küçültülmüş bir font dosyası üretir. Bu otomatik çalışır, elle bir şey yapman gerekmez — ama IconData'yı dinamik (çalışma zamanında hesaplanan) bir şekilde kullanırsan (örn. bir Map'ten okuyarak), Flutter hangi ikonların kullanılacağını önceden bilemez ve bu optimizasyon devre dışı kalır.
Obfuscation (Kod Gizleme)
Neden Gerekli?
flutter build apk --obfuscate --split-debug-info=build/debug-infoNormalde, bir Dart/Flutter uygulamasının AOT-derlenmiş (Bölüm 1'de öğrendiğimiz derleme türü) hali bile, sınıf isimleri, fonksiyon isimleri gibi okunabilir bilgiler içerir — biri, senin .apk'nı açıp inceleyerek, kodunun yapısını (sınıf/fonksiyon isimlerinden yola çıkarak) kısmen anlayabilir. --obfuscate, bu isimleri anlamsız kısa kodlara (a, b, Xy3 gibi) dönüştürür — kodun çalışma mantığını değiştirmeden, okunabilirliğini ortadan kaldırır.
--split-debug-info=build/debug-info — obfuscation'ın bir maliyeti var: bir kullanıcının cihazında bir çökme (crash) olduğunda, normalde hata raporu okunabilir fonksiyon isimleri içerir; obfuscate edilmiş bir build'de bu isimler anlamsız kodlara dönüştüğü için, hata raporu da anlamsız olur. --split-debug-info, obfuscation sırasında hangi anlamsız kodun hangi gerçek isme karşılık geldiğini tutan bir eşleme dosyası üretir — bu dosyayı güvenli bir yerde saklarsın (Play Store'a da yüklenebilir), ve bir çökme raporunu bu dosyayla "deobfuscate" ederek (Konu 53'te tanıdığımız Firebase'in Crashlytics gibi araçları bunu otomatik yapar) tekrar okunabilir hale getirirsin.
Pratik tavsiye: Obfuscation, hassas iş mantığı (örn. bir fiyatlandırma algoritması) içeren ticari uygulamalarda değerlidir; basit bir hobi projesinde genelde gerekli değildir.
Flavor Yönetimi — Aynı Kod Tabanından Birden Fazla Sürüm
Sorunu Tanımlayalım
Gerçek bir geliştirme sürecinde, genelde üç ortamın aynı anda cihazında kurulu olmasını istersin:
Dev → geliştirme sırasında test ettiğin, sahte/test API'sine bağlı sürüm
Staging → gerçek API'ye yakın, yayın öncesi son test ortamı
Prod → gerçek kullanıcıya gidecek, üretim API'sine bağlı sürümFlavor'lar (Android'de "product flavor", iOS'ta "scheme"), aynı Dart kodundan, farklı applicationId/Bundle Identifier, farklı uygulama ikonu/ismi, ve farklı yapılandırma (API URL'si gibi) ile birbirinden bağımsız üç ayrı uygulama üretmeni sağlar — üçü de aynı cihaza, aynı anda kurulabilir (farklı applicationId'ler sayesinde, sistem onları farklı uygulamalar sanır).
Android Tarafı — build.gradle
android {
flavorDimensions "ortam"
productFlavors {
dev {
dimension "ortam"
applicationIdSuffix ".dev" // com.senirket.uygulaman.dev
resValue "string", "app_name", "Uygulamam (Dev)"
}
prod {
dimension "ortam"
resValue "string", "app_name", "Uygulamam"
}
}
}applicationIdSuffix ".dev" — Konu 44'te öğrendiğimiz applicationId'nin sonuna bir ek getirerek, dev ve prod sürümlerinin Play Store/cihaz açısından tamamen farklı uygulamalar olmasını sağlıyor.
Dart Tarafı — Ortama Özel Giriş Noktaları
// lib/main_dev.dart
import 'app_config.dart';
import 'main.dart' as app;
void main() {
AppConfig.apiUrl = 'https://dev-api.ornek.com';
app.main();
}// lib/main_prod.dart
import 'app_config.dart';
import 'main.dart' as app;
void main() {
AppConfig.apiUrl = 'https://api.ornek.com';
app.main();
}// lib/app_config.dart
class AppConfig {
static late String apiUrl; // Dart Bölüm 2 — late, geç atanacak alan
}Bu kalıp neden işe yarıyor? Dart Bölüm 12'de öğrendiğimiz import ... as (isim çakışmasını önleme) burada kritik — her flavor'ın kendi main_X.dart dosyası, ortak main.dart'ı (asıl uygulama) farklı bir yapılandırmayla çağırıyor. AppConfig.apiUrl, Bölüm 5 Konu 20'de http/dio çağrılarında kullandığın temel URL'in artık sabit kodlanmış olmadığı, flavor'a göre değiştiği anlamına geliyor.
flutter run --flavor dev -t lib/main_dev.dart
flutter build apk --flavor prod -t lib/main_prod.dart--flavor dev, Android/iOS'a hangi flavor'ı derleyeceğini söyler; -t lib/main_dev.dart (target), Dart tarafına hangi giriş noktasından başlayacağını söyler — bu ikisinin birlikte verilmesi gerekir, biri native tarafı, diğeri Dart tarafını yapılandırıyor.
iOS Tarafı — Xcode Schemes
iOS'ta aynı fikir, Xcode Scheme'leri ve Configuration'lar ile uygulanır — Konu 44'te öğrendiğimiz Runner.xcworkspace içinde, her flavor için ayrı bir scheme (Dev/Staging/Prod) tanımlanır, her biri kendi Bundle Identifier'ına ve Info.plist ayarlarına sahip olur. Bu kısım genelde Xcode arayüzünden elle yapılandırılır — CLI tarafından tam otomatik değildir, Android'e göre biraz daha manuel bir süreçtir.
flutter_flavorizr — Kurulumu Otomatikleştiren Bir Paket
flutter pub add dev:flutter_flavorizrYukarıdaki Android + iOS + Dart yapılandırmasının hepsini elle kurmak, özellikle iOS tarafında hataya açık ve tekrarlayıcı bir iştir — flutter_flavorizr, pubspec.yaml'a yazacağın bir yapılandırmadan, bu dosyaların çoğunu otomatik üretir. Bu, Dart Bölüm 13'te öğrendiğimiz build_runner/code generation felsefesinin, build sistemi yapılandırmasına uygulanmış hali.
Bölüm 11'i Kapatırken — Yayınlama Sürecinin Tam Resmi
Kod yaz (Bölüm 1-10)
→ flavor'lara göre yapılandır (dev/staging/prod)
→ boyutu analiz et (--analyze-size), gerekiyorsa küçült
→ obfuscate et (--obfuscate), debug-info'yu sakla
→ imzala (Konu 44 + Konu 53'teki Play App Signing)
→ test track'lerinden geçir (iç → kapalı → açık)
→ staged rollout ile üretime çık🎯 Bu Dersten Çıkarılması Gerekenler
--analyze-size, hangi paketin/varlığın uygulamanın boyutunu ne kadar etkilediğini ölçerek gösterir;--split-per-abi, Play Store dışı dağıtımda mimariye özel küçük APK'lar üretir (Store'da bu işi zaten.aabyapıyor).- İkon tree-shaking, kullanılan
Icons.ikonlarını otomatik tespit edip font dosyasını küçültür — dinamik ikon kullanımı bunu devre dışı bırakabilir. --obfuscate, kod okunabilirliğini kaldırır;--split-debug-info, obfuscate edilmiş çökme raporlarını tekrar okunabilir hale getirmek için gereken eşleme dosyasını üretir.- Flavor'lar, aynı kod tabanından farklı
applicationId/Bundle Identifier, isim, ikon ve yapılandırmayla (dev/staging/prod) bağımsız uygulamalar üretmeni sağlar. --flavor(native yapılandırma) ve-t(Dart giriş noktası) birlikte kullanılır;flutter_flavorizr, bu kurulumu büyük ölçüde otomatikleştirir.
📝 Ödevler
- [ ]
flutter build apk --analyze-sizeçalıştır, raporu DevTools'ta aç, en büyük 3 bileşeni tespit et. - [ ]
--obfuscate --split-debug-infoile bir release build üret, üretilen debug-info dosyasının ne işe yaradığını kendi cümlelerinle açıkla. - [ ] Android tarafında
dev/prodflavor'ları kur (farklıapplicationIdSuffixve uygulama ismiyle),main_dev.dart/main_prod.dartgiriş noktalarını oluştur, ikisini aynı cihaza aynı anda kurup farklı uygulamalar olduklarını doğrula. - [ ]
AppConfig.apiUrl'i her flavor için farklı bir sahte URL'e ayarla, hangi flavor'ın hangi URL'i kullandığını ekranda göster. - [ ] Kendi cümlelerinle, "neden
.aab+ Play App Signing kullanan bir uygulamanın,--split-per-abi'ye genelde ihtiyaç duymadığını" açıkla.
🎮 Mini Uygulama — Bölüm 11 Checkpoint: Yayına Hazır Uygulama
Bölüm 11'in tamamını (Firebase/Supabase, versiyonlama, boyut/obfuscation, flavor) birleştiren bir mini proje:
Gereksinimler:
- Bölüm 11 Konu 50 veya 51'de kurduğun Auth + veritabanı akışını temel alan basit bir uygulama.
dev/prodiki flavor kur, her biri farklı bir Firebase/Supabase projesine (ya da en azından farklı bir sahte API URL'sine) bağlansın.pubspec.yaml'da anlamlı bir semantic version + build number akışı uygula (Konu 53'ü hatırla).--analyze-sizeile boyutu ölç, en az bir optimizasyon (örn. kullanılmayan bir paketi kaldırma) uygula ve öncesi/sonrası boyutu karşılaştır.- Release modda,
--obfuscateile bir build üret. - Bonus:
flutter build appbundle --flavor prodile üretilen.aab'yi, (bir Play Console hesabın varsa) iç test track'ine yükle.
Bölüm 11 tamamlandı. Sıradaki konu: Bölüm 12 — Konu 55: Flutter Web / Desktop (Uzmanlık Seviyesi Başlangıcı)