↑↓ seç · Enter aç · Esc kapat

Mutlu Tekin
Mutlu Tekin
← Yazılar

Bölüm 9 — Konu 44: Android/iOS Build Sistemleri

6 dk okuma #flutter
Dizi · 44/61 Flutter Türkçe Tutorial
  1. Bölüm 1 — Konu 1: Flutter Nedir, Mimarisi (Widget → Element → RenderObject, Skia/Impeller)
  2. Bölüm 1 — Konu 2: Ortam Kurulumu (Flutter SDK, Android Studio/VS Code, Emulator/Simulator, DevTools'a İlk Bakış)
  3. Bölüm 1 — Konu 3: İlk Proje Yapısı (`pubspec.yaml`, `lib/`, Klasör Mimarisi, `flutter create` Anatomisi)
  4. Bölüm 1 — Konu 4: Hot Reload / Hot Restart Ne Yapıyor, Neden Önemli
  5. Bölüm 2 — Konu 5: "Her Şey Widget'tır" Felsefesi, Widget Ağacı
  6. Bölüm 2 — Konu 6: StatelessWidget vs StatefulWidget + `setState()` Derinlemesine (Rebuild Mekanizması)
  7. Bölüm 2 — Konu 7: Temel Layout — Container, Row, Column, Stack, Padding, Align, Center
  8. Bölüm 2 — Konu 8: Constraint Sistemi — "Constraints Go Down, Sizes Go Up, Parent Sets Position"
  9. Bölüm 2 — Konu 9: `Expanded`, `Flexible`, `Spacer`, Intrinsic Widget'lar
  10. Bölüm 3 — Konu 10: MaterialApp/CupertinoApp, Scaffold, AppBar
  11. Bölüm 3 — Konu 11: `ListView`, `GridView`, `SingleChildScrollView` (+ Builder Pattern)
  12. Bölüm 3 — Konu 12: Text, TextStyle, Icon, Image, Asset Yönetimi
  13. Bölüm 3 — Konu 13: Custom Widget Yazma Prensipleri (Composition Over Inheritance)
  14. Bölüm 3 — Konu 14: Navigator 1.0 — Push/Pop, Named Routes
  15. Bölüm 4 — Konu 15: Form, TextField/TextFormField, GlobalKey<FormState>, Validasyon
  16. Bölüm 4 — Konu 16: Theme Sistemi (ThemeData, ColorScheme)
  17. Bölüm 4 — Konu 17: Responsive & Adaptive Tasarım (MediaQuery, LayoutBuilder, OrientationBuilder, Breakpoint Stratejileri)
  18. Bölüm 5 — Konu 18: Future/Async-Await Flutter Bağlamında, FutureBuilder
  19. Bölüm 5 — Konu 19: `Stream`, `StreamBuilder`
  20. Bölüm 5 — Konu 20: HTTP İstekleri (`http` / `dio` Paketleri)
  21. Bölüm 5 — Konu 21: JSON Serialization (Manuel → `json_serializable`/`freezed`)
  22. Bölüm 5 — Konu 22: Local Storage — `shared_preferences` → `Hive` → `sqflite`/Drift
  23. Bölüm 6 — Konu 23: InheritedWidget ve InheritedModel — "Neden setState Yetmiyor" Sorusunun Cevabı
  24. Bölüm 6 — Konu 24: Provider Paketi
  25. Bölüm 6 — Konu 25: Riverpod (Modern Yaklaşım, Provider'ın Halefi)
  26. Bölüm 6 — Konu 26: BLoC/Cubit Pattern (`flutter_bloc`)
  27. Bölüm 6 — Konu 27: GetX (Tartışmalı Ama Yaygın)
  28. Bölüm 6 — Konu 28: Karşılaştırma — Hangi Projede Hangisi?
  29. Bölüm 7 — Konu 29: Navigator 2.0 (Router, RouteInformationParser, RouterDelegate)
  30. Bölüm 7 — Konu 30: `go_router` Paketi (Pratik ve Modern Çözüm)
  31. Bölüm 7 — Konu 31: Deep Linking
  32. Bölüm 7 — Konu 32: Repository Pattern, Katmanlı Mimari (Data/Domain/Presentation)
  33. Bölüm 7 — Konu 33: Dependency Injection (`get_it`, `injectable`)
  34. Bölüm 7 — Konu 34: Clean Architecture Uyarlaması, SOLID Prensipleri
  35. Bölüm 8 — Konu 35: Implicit Animasyonlar
  36. Bölüm 8 — Konu 36: Explicit Animasyonlar (`AnimationController`, `Tween`, `Curve`)
  37. Bölüm 8 — Konu 37: Hero Animasyonları
  38. Bölüm 8 — Konu 38: `CustomPainter` / `Canvas`
  39. Bölüm 8 — Konu 39: Rive / Lottie Entegrasyonu
  40. Bölüm 9 — Konu 40: Platform Channels
  41. Bölüm 9 — Konu 41: Permission Yönetimi (`permission_handler`)
  42. Bölüm 9 — Konu 42: Kamera, Konum, Sensörler
  43. Bölüm 9 — Konu 43: Push Notification (Firebase Cloud Messaging)
  44. Bölüm 9 — Konu 44: Android/iOS Build Sistemleri
  45. Bölüm 10 — Konu 45: Test Yazımı (Unit, Widget, Integration, Golden)
  46. Bölüm 10 — Konu 46: CI/CD
  47. Bölüm 10 — Konu 47: Rebuild Optimizasyonu (`const`, `key` Kullanımı)
  48. Bölüm 10 — Konu 48: DevTools Profiling
  49. Bölüm 10 — Konu 49: Lazy Loading, Pagination, Büyük Liste Performansı
  50. Bölüm 11 — Konu 50: Firebase Ekosistemi (Auth, Firestore, Storage, Functions)
  51. Bölüm 11 — Konu 51: Supabase Alternatifi
  52. Bölüm 11 — Konu 52: GraphQL (Opsiyonel)
  53. Bölüm 11 — Konu 53: Store Yayınlama Süreci (İmzalama, Listing, Versiyonlama)
  54. Bölüm 11 — Konu 54: App Size, Obfuscation, Flavor Yönetimi
  55. Bölüm 12 — Konu 55: Flutter Web / Desktop
  56. Bölüm 12 — Konu 56: Custom `RenderObject` Yazımı
  57. Bölüm 12 — Konu 57: Engine Mimarisi Derinlemesine (Impeller vs Skia)
  58. Bölüm 12 — Konu 58: Plugin Geliştirme, pub.dev'e Paket Yayınlama
  59. Bölüm 12 — Konu 59: Monorepo Mimarisi (Melos)
  60. Bölüm 12 — Konu 60: Erişilebilirlik (Accessibility) Derinlemesine
  61. Bölüm 12 — Konu 61: Yerelleştirme (Localization / i18n)
Dizinin sayfası →
İçindekiler 11 başlık
  1. Flutter Projesinin Altında İki Ayrı "Native Proje" Yatıyor
  2. Android — Gradle Sistemi
  3. flutter build Komutları — APK vs App Bundle (AAB)
  4. Build Türleri — Debug, Profile, Release
  5. İmzalama (Signing) — Neden Zorunlu?
  6. iOS — Xcode ve CocoaPods
  7. Android ile iOS Build Sistemleri — Karşılaştırma
  8. Sık Karşılaşılan Build Sorunları — Nereye Bakmalı?
  9. 🎯 Bu Dersten Çıkarılması Gerekenler
  10. 📝 Ödevler
  11. 🎮 Mini Uygulama — Bölüm 9 Checkpoint: İzin ve Native Entegrasyon Merkezi

Bölüm 9'un son konusu. Şimdiye kadar hep flutter run ile geliştirme yaptık — bu derste, flutter run'ın arka planda gerçekte ne yaptığını ve bir uygulamayı dağıtılabilir bir dosyaya (APK, AAB, IPA) nasıl dönüştürdüğünü öğreneceğiz. Mağazaya yayınlama sürecinin kendisini Bölüm 11'de göreceğiz — bu ders, ona giden build mekanizmasına odaklanıyor.

Flutter Projesinin Altında İki Ayrı "Native Proje" Yatıyor

Bölüm 1 Konu 3'te flutter create ile oluşan klasör yapısını görmüştük — lib/ klasörü (senin Dart kodun) dışında, iki klasör daha vardı:

metin
android/    # tam teşekküllü bir Android (Gradle) projesi
ios/        # tam teşekküllü bir iOS (Xcode) projesi

Önemli gerçek: Bunlar "sahte" ya da "yardımcı" dosyalar değil — android/ klasörü, Android Studio'da doğrudan açılabilen, ios/ klasörü Xcode'da doğrudan açılabilen, gerçek native projelerdir. Flutter, senin Dart kodunu derleyip, bu native projelerin içine bir kütüphane olarak yerleştirir. Bu yüzden Android build sistemini (Gradle) ve iOS build sistemini (Xcode/CocoaPods) en azından temel düzeyde anlamak, "build hatası" ile karşılaştığında nereye bakman gerektiğini bilmen için önemlidir.

Android — Gradle Sistemi

metin
android/
├── build.gradle              # PROJE geneli ayarlar (repository'ler, Kotlin sürümü)
├── app/
│   └── build.gradle          # UYGULAMA'ya özel ayarlar (applicationId, sürüm, imzalama)
└── app/src/main/AndroidManifest.xml  # izinler (Konu 41), uygulama adı, ikon

app/build.gradle içinde göreceğin en önemli alanlar:

gradle
android {
    defaultConfig {
        applicationId "com.senirket.uygulaman" // Play Store'daki BENZERSİZ kimliğin
        minSdkVersion 21   // desteklenen EN ESKİ Android sürümü
        targetSdkVersion 34 // test edilip ONAYLANDIĞIN Android sürümü
        versionCode 1       // her yayında ARTMASI gereken tam sayı (Play Store bunu takip eder)
        versionName "1.0.0" // kullanıcıya GÖRÜNEN sürüm numarası
    }
}

applicationId, Dart Bölüm 6'da öğrendiğimiz benzersiz tanımlayıcı kavramına benzer — Play Store'da bir kere kullanılır, yayınladıktan sonra değiştirilemez. versionCode ile versionName arasındaki fark önemli: versionCode makine içindir (Play Store, hangi sürümün daha yeni olduğunu bununla anlar — her yayında kesinlikle artmalı), versionName ise insan içindir (kullanıcının Play Store'da gördüğü "1.0.0" gibi bir metin).

flutter build Komutları — APK vs App Bundle (AAB)

bash
flutter build apk       # tek, kurulabilir bir .apk dosyası üretir
flutter build appbundle # Play Store'un istediği .aab formatı üretir

Aradaki fark, dağıtım şekli: .apk, doğrudan kurulabilen tam bir paket — test amaçlı, ya da Play Store dışı dağıtım (bir web sitesinden indirme gibi) için kullanılır. .aab (Android App Bundle), Play Store'a yüklediğin format — Play Store, bu dosyadan, her cihazın kendi özelliklerine (ekran çözünürlüğü, işlemci mimarisi, dil) göre optimize edilmiş, küçültülmüş bir APK kendisi üretip o cihaza gönderir. Pratik kural: Play Store'a yayınlayacaksan appbundle, elle test/dağıtım için apk.

Build Türleri — Debug, Profile, Release

Dart Bölüm 1'de öğrendiğimiz JIT (Just-In-Time) vs AOT (Ahead-Of-Time) derleme ayrımını hatırlarsan — Flutter'ın üç build türü, tam olarak bu ayrıma dayanır:

Build Türü Derleme Ne Zaman Kullanılır
Debug JIT — hot reload çalışır Günlük geliştirme (flutter run'ın varsayılanı)
Profile AOT — ama profiling araçları açık Performans ölçümü (Bölüm 10'da DevTools ile)
Release AOT — tüm optimizasyonlar açık, debug bilgisi yok Gerçek kullanıcıya dağıtım
bash
flutter run                    # debug (varsayılan)
flutter run --profile
flutter run --release
flutter build apk --release    # build komutlarında varsayılan zaten release'tir

Neden bu ayrım önemli? Debug build'ler, hot reload'ı mümkün kılmak için ekstra kod ve kontrol taşır — bu, uygulamayı belirgin şekilde yavaşlatır. Bir arkadaşına "uygulamam çok yavaş" diye şikayet etmeden önce, release build ile test etmen gerekir — debug build'in performansı, gerçek kullanıcı deneyimini asla yansıtmaz.

İmzalama (Signing) — Neden Zorunlu?

Android, kimliği doğrulanmamış bir APK'nın Play Store'a yüklenmesine izin vermez — her release build'in bir imza (dijital sertifika) ile işaretlenmesi gerekir. Bu, Dart Bölüm 8'de öğrendiğimiz hata yönetimi kadar teknik olmayan, daha çok bir güvenlik/kimlik mekanizması: "bu uygulamanın gerçekten senden geldiğini" kanıtlıyor.

bash
keytool -genkey -v -keystore ~/anahtar.jks -keyalg RSA -keysize 2048 -validity 10000 -alias anahtarim

Bu komutla oluşturduğun .jks dosyası (keystore), android/app/build.gradle'a bağlanır ve her --release build'inde otomatik olarak kullanılır. Kritik uyarı: Bu dosyayı kaybetmemen gerekir — kaybedersen, var olan uygulamanı bir daha güncelleyemezsin (Play Store, farklı bir imzayla gelen güncellemeyi reddeder). İmzalama sürecinin tam adımlarını Bölüm 11 Konu 53'te (Store yayınlama süreci) detaylı işleyeceğiz.

iOS — Xcode ve CocoaPods

metin
ios/
├── Runner.xcworkspace     # Xcode'da AÇILMASI gereken dosya (Runner.xcodeproj DEĞİL!)
├── Runner/Info.plist      # izinler (Konu 41), uygulama adı, Bundle Identifier
└── Podfile                 # CocoaPods bağımlılıkları

Runner.xcworkspace vs Runner.xcodeproj — bu, iOS geliştirmeye yeni başlayanların sık düştüğü bir tuzak: pubspec.yaml'daki paketlerin native tarafındaki (iOS) kısımları, CocoaPods (iOS'un paket yöneticisi, Dart'ın pubuna benzer bir rolü var) ile yönetilir. CocoaPods, bu bağımlılıkları bir araya getiren bir .xcworkspace dosyası oluşturur — sen her zaman bu dosyayı açmalısın, .xcodeproj'u değil (o, sadece ana projeyi, eklenen paketler olmadan gösterir).

Info.plist, Konu 41'de gördüğümüz izin açıklamalarının (NSCameraUsageDescription gibi) yanı sıra, uygulamanın Bundle Identifier'ını da (Android'deki applicationId'nin iOS karşılığı, örn. com.senirket.uygulaman) tutar.

bash
flutter build ios    # simülatör/cihaz için (imzasız, test amaçlı)
flutter build ipa    # App Store'a yüklenebilir .ipa dosyası (imzalı)

iOS'ta imzalama daha karmaşıktır — bir Apple Developer hesabı (yıllık ücretli), bir imzalama sertifikası, ve bir provisioning profile (hangi cihazlarda/hangi özelliklerle çalışabileceğini tanımlayan bir dosya) gerektirir. Bu süreç, genelde Xcode'un kendi arayüzü üzerinden "Automatically manage signing" seçeneğiyle büyük ölçüde otomatikleştirilir — elle sertifika/profil yönetimi, genelde kurumsal/takım senaryolarında gerekir.

Android ile iOS Build Sistemleri — Karşılaştırma

Android (Gradle) iOS (Xcode/CocoaPods)
Benzersiz kimlik applicationId Bundle Identifier
Paket yöneticisi Gradle (Maven repository'leri) CocoaPods
Dağıtım formatı .apk (test) / .aab (Store) .ipa
İmzalama Keystore (.jks) — sen oluşturursun Sertifika + provisioning profile — Apple onaylar
Geliştirme maliyeti Ücretsiz (Play Store kaydı bir kerelik $25) Apple Developer hesabı (yıllık ~$99)
Açılması gereken dosya (Android Studio otomatik bulur) Runner.xcworkspace (.xcodeproj DEĞİL)

Sık Karşılaşılan Build Sorunları — Nereye Bakmalı?

  • "Gradle build failed" → android/build.gradle veya android/app/build.gradle'da bir sürüm çakışması, ya da bir paketin Android tarafındaki native kodunda sorun.
  • "CocoaPods could not find compatible versions" → ios/Podfile.lock'ı silip cd ios && pod install çalıştırmak, çoğu zaman çözer.
  • "No provisioning profile found" → Apple Developer hesabı/sertifika sorunları — Xcode'un "Signing & Capabilities" sekmesine bakılır.
  • Debug build'de yavaşlık şikayeti → muhtemelen sorun değil, release build ile tekrar test et.

🎯 Bu Dersten Çıkarılması Gerekenler

  • android/ ve ios/ klasörleri, gerçek native projelerdir — Flutter, Dart kodunu bunların içine bir kütüphane olarak yerleştirir.
  • Android'de applicationId/versionCode/versionName, app/build.gradle'da tanımlanır; .apk test/dağıtım, .aab Play Store içindir.
  • Build türleri (debug/profile/release), Dart'ın JIT/AOT derleme ayrımına dayanır — performans şikayetleri her zaman release build ile doğrulanmalıdır.
  • Android imzalama bir keystore (.jks) ile sendeyken, iOS imzalama Apple Developer hesabı + sertifika + provisioning profile gerektirir.
  • iOS'ta her zaman Runner.xcworkspace açılmalı (CocoaPods bağımlılıklarını içerir), Runner.xcodeproj değil.

📝 Ödevler

  • [ ] Bir Flutter projesinde android/app/build.gradle'ı aç, applicationId, minSdkVersion, versionCode/versionName alanlarını bul ve her birinin ne işe yaradığını kendi cümlelerinle yaz.
  • [ ] flutter build apk --release ve flutter build appbundle --release komutlarını çalıştır, oluşan dosyaların boyutunu ve konumunu karşılaştır.
  • [ ] Aynı uygulamayı debug ve release modda çalıştırıp (flutter run vs flutter run --release), açılış hızındaki farkı gözlemle.
  • [ ] (Mac kullanıyorsan) ios/Runner.xcworkspace'i Xcode'da aç, "Signing & Capabilities" sekmesinde Bundle Identifier'ı bul.
  • [ ] Kendi cümlelerinle, "neden .aab formatının Play Store için .apk'dan daha avantajlı olduğunu" açıkla.

🎮 Mini Uygulama — Bölüm 9 Checkpoint: İzin ve Native Entegrasyon Merkezi

Bölüm 9'un tamamını (platform channels, izinler, kamera/konum/sensör, push notification, build) test eden bir mini proje:

Gereksinimler:

  • Tek bir ekranda, sırayla şu özelliklerin her biri için durum gösteren ve tetikleyen bir buton/kart olsun: kamera izni (Konu 41), konum alma (Konu 42), ivmeölçer canlı verisi (Konu 42).
  • Her kart, PermissionStatus'a göre farklı bir görsel durum göstersin (granted: yeşil, denied: sarı, permanentlyDenied: kırmızı + "Ayarlara Git" butonu).
  • (Firebase kurulumun varsa) FCM token'ını ekranda göster, bir test bildirimi gönderip onMessage ile yakalayıp flutter_local_notifications ile göster.
  • Uygulamayı hem debug hem release modda çalıştırıp, tüm özelliklerin her ikisinde de çalıştığını doğrula.
  • Bonus: flutter build apk --release ile gerçek bir APK üret, kendi Android cihazına yükleyip test et.

Bölüm 9 tamamlandı. Sıradaki konu: Bölüm 10 — Konu 45: Test Yazımı (Unit, Widget, Integration, Golden Test)