Bölüm 12 — Konu 55: Flutter Web / Desktop
Dizi · 55/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 13 başlık
- Flutter, Tek Kod Tabanından Kaç Platformu Hedefler?
- Web — Nasıl Çalışır?
- Render Motorları — Güncel Durum
- Web'in Kendine Özgü Sınırlamaları
- dart:io Web'de Çalışmaz
- Koşullu İçe Aktarma (Conditional Imports) — Çözüm
- kIsWeb — Çalışma Zamanında Platform Kontrolü
- Masaüstü (Windows/macOS/Linux) — Web'den Farklı Bir Dünya
- Masaüstüne Özgü Etkileşim Kalıpları
- Pencere Yönetimi — window_manager Paketi
- Responsive Tasarımın Önemi Katlanıyor
- 🎯 Bu Dersten Çıkarılması Gerekenler
- 📝 Ödevler
Bölüm 12'ye ("Uzmanlık Seviyesi") hoş geldin — bu son bölüm, seni "Flutter biliyorum"dan "Flutter'ın iç mekanizmalarına hakimim" seviyesine taşıyor. İlk konu: şimdiye kadar yazdığın aynı Dart kodunun, mobil dışında web tarayıcısında ve masaüstünde (Windows/macOS/Linux) nasıl çalıştığı.
Flutter, Tek Kod Tabanından Kaç Platformu Hedefler?
Bölüm 1 Konu 1'de öğrendiğimiz Skia/Impeller mimarisini hatırla — Flutter, kendi piksellerini kendi çizdiği için, teorik olarak her platformda aynı görünümü üretebilir. Bugün resmi olarak desteklenen platformlar: Android, iOS, Web, Windows, macOS, Linux — hepsi aynı lib/ klasöründen.
flutter config --list # şu an hangi platformlar açık, gör
flutter create --platforms=web,windows,macos,linux . # var olan projeye platform ekleWeb — Nasıl Çalışır?
flutter run -d chromeFlutter web, Dart kodunu JavaScript'e (ya da WebAssembly'ye) derleyip, Skia'nın web'e taşınmış bir versiyonuyla (CanvasKit) tarayıcının <canvas> elemanı üzerine piksel piksel çizer. Bu, Bölüm 1'de öğrendiğimiz "Flutter, native UI bileşenlerini kullanmaz, kendi çizer" ilkesinin, web'de de aynen geçerli olduğu anlamına gelir — bir Flutter web sayfası, normal bir HTML/CSS sayfası gibi yapılandırılmamıştır, tek bir <canvas> içine çizilmiş bir resim gibi düşünülebilir (etkileşimli olsa da).
Render Motorları — Güncel Durum
Flutter web'in render motoru, zaman içinde değişti — bu, tam da senin "güncelliğe dikkat" isteğinin tam yerinde olduğu bir konu:
- CanvasKit (WebAssembly ile derlenmiş Skia) — varsayılan ve önerilen render motoru; mobil/masaüstüyle piksel piksel aynı görünümü garanti eder.
- Skwasm — CanvasKit'in WebAssembly + çoklu iş parçacığı (multi-threading) kullanan, daha yeni ve deneysel/gelişmekte olan bir varyantı; tarayıcı desteğine bağlı olarak daha yüksek performans hedefler.
- HTML renderer — artık kaldırıldı. Eskiden (Flutter'ın erken web sürümlerinde) daha küçük indirme boyutu sunan, DOM/CSS tabanlı bir alternatifti, ama piksel tutarlılığı CanvasKit kadar güçlü değildi — Flutter ekibi, CanvasKit/Skwasm'ı tek, tutarlı bir standart haline getirmek için bunu kaldırdı. Eski kaynaklarda
--web-renderer htmlgibi bayraklar görebilirsin — bunlar artık geçerli değil.
Pratik sonuç: Web'e build alırken render motoru seçme derdin yok — Flutter, senin için en uygun olanı (CanvasKit, uygun tarayıcılarda Skwasm) otomatik seçiyor.
Web'in Kendine Özgü Sınırlamaları
dart:io Web'de Çalışmaz
import 'dart:io'; // ❌ WEB'DE DERLEME HATASI VERİRDart Bölüm 13'te öğrendiğimiz dart:io (dosya sistemi, soket bağlantıları), tarayıcı ortamında anlamsızdır — bir web sayfası, kullanıcının dosya sistemine doğrudan erişemez (güvenlik nedeniyle). File, Directory, Socket gibi sınıfları kullanan bir paket (örn. Bölüm 9'da gördüğümüz bazı native paketler), web'de derlenemez.
Koşullu İçe Aktarma (Conditional Imports) — Çözüm
// depolama_servisi.dart (arayüz)
abstract class DepolamaServisi {
Future<void> kaydet(String anahtar, String deger);
}
// depolama_servisi_io.dart (mobil/masaüstü — dart:io kullanabilir)
import 'dart:io';
class DepolamaServisiIO implements DepolamaServisi { /* ... */ }
// depolama_servisi_web.dart (web — dart:io YOK, farklı bir yaklaşım)
import 'package:web/web.dart' as web; // tarayıcı API'lerine erişim
class DepolamaServisiWeb implements DepolamaServisi { /* ... */ }// depolama_servisi_factory.dart
import 'depolama_servisi.dart';
import 'depolama_servisi_io.dart'
if (dart.library.html) 'depolama_servisi_web.dart'; // KOŞULLU import!
DepolamaServisi depolamaServisiOlustur() {
return DepolamaServisiIO(); // web'de derlenirken OTOMATİK olarak Web versiyonuyla değişir
}if (dart.library.html) '...' — bu, Dart'ın derleme zamanında platforma göre hangi dosyanın kullanılacağına karar vermesini sağlayan bir mekanizma. Bu, Bölüm 7'de öğrendiğimiz Dependency Inversion prensibinin (soyut bir arayüze bağımlı olma, somut implementasyonu dışarıdan "enjekte etme") derleme zamanı versiyonu — DI genelde çalışma zamanında (get_it ile) karar verirken, koşullu import derleme zamanında karar veriyor.
kIsWeb — Çalışma Zamanında Platform Kontrolü
import 'package:flutter/foundation.dart' show kIsWeb;
if (kIsWeb) {
print('Web\'de çalışıyoruz');
} else {
print('Native bir platformdayız (mobil/masaüstü)');
}kIsWeb, Dart Bölüm 2'de öğrendiğimiz sabit (const) bir boolean — belirli bir davranış farkını (örn. bir dosya indirme butonunun web'de farklı çalışması) if ile koşullu olarak yönetmen gerektiğinde kullanılır. Koşullu import'tan farkı: kIsWeb, aynı dosya içinde, çalışma zamanı mantığı için; koşullu import, hangi dosyanın derleneceğini belirlemek için.
Masaüstü (Windows/macOS/Linux) — Web'den Farklı Bir Dünya
flutter run -d windows # veya -d macos, -d linuxMasaüstü, web'in aksine, native bir uygulama olarak derlenir (Bölüm 9 Konu 44'te öğrendiğimiz mobil build mekaniğine kavramsal olarak çok benzer, ama Windows .exe, macOS .app, Linux için genelde bir paket formatı üretir) — dart:io sorunsuz çalışır.
Masaüstüne Özgü Etkileşim Kalıpları
MouseRegion(
onEnter: (olay) => setState(() => _uzerindeMi = true),
onExit: (olay) => setState(() => _uzerindeMi = false),
child: Container(
color: _uzerindeMi ? Colors.blue[100] : Colors.white,
child: const Text('Üzerine gel'),
),
)MouseRegion, mobilde anlamsız (dokunmatik ekranda "hover" yoktur) ama masaüstünde (ve web'de, fare kullanıldığında) kritik bir widget — Dart Bölüm 5'te öğrendiğimiz callback kalıbının (onEnter/onExit), fare imlecinin widget üzerine gelip gelmediğini izlemek için kullanımı.
Shortcuts(
shortcuts: {
LogicalKeySet(LogicalKeyboardKey.control, LogicalKeyboardKey.keyS):
const KaydetIntent(),
},
child: Actions(
actions: {
KaydetIntent: CallbackAction<KaydetIntent>(onInvoke: (intent) => kaydet()),
},
child: Focus(autofocus: true, child: const AnaEkran()),
),
)Klavye kısayolları (Ctrl+S gibi), masaüstü uygulamalarının temel beklentisi — Shortcuts + Actions widget'ları, Bölüm 7'de öğrendiğimiz Command pattern'e (bir eylemi bir "niyet" nesnesiyle temsil etme) benzer bir yapıda çalışır: LogicalKeySet, hangi tuş kombinasyonunun; Intent (burada KaydetIntent), "ne yapılmak istendiğini"; Action, "gerçekte ne olacağını" tanımlar — bu üçlü ayrım, aynı kısayolu farklı ekranlarda farklı davranışlara bağlamanı kolaylaştırır.
Pencere Yönetimi — window_manager Paketi
flutter pub add window_managervoid main() async {
WidgetsFlutterBinding.ensureInitialized();
await windowManager.ensureInitialized();
WindowOptions windowOptions = const WindowOptions(
size: Size(1024, 768),
minimumSize: Size(600, 400),
center: true,
);
windowManager.waitUntilReadyToShow(windowOptions, () async {
await windowManager.show();
});
runApp(const MyApp());
}Flutter'ın kendisi, pencere boyutu/konumu gibi işletim sistemi seviyesi özellikleri yerleşik olarak sunmaz (bu, mobilde "ekran boyutu" kavramının sabit olmasından farklı olarak, masaüstünde pencere yeniden boyutlandırılabilir, taşınabilir). window_manager, Bölüm 9 Konu 40'ta öğrendiğimiz platform channel mekanizmasının üzerine inşa edilmiş, pencere yönetimini Dart API'sine taşıyan bir pakettir.
Responsive Tasarımın Önemi Katlanıyor
Bölüm 4 Konu 17'de öğrendiğimiz MediaQuery/LayoutBuilder ile responsive tasarım, mobilde genelde "telefon vs tablet" ayrımıydı — web/masaüstünde, kullanıcı pencereyi istediği gibi boyutlandırabilir (küçük bir pencere, tam ekran, ultra geniş bir monitör). Bu yüzden, web/masaüstü hedefleyen bir uygulamada, Konu 17'deki breakpoint stratejisi "olsa iyi olur" değil, "zorunlu" hale gelir.
🎯 Bu Dersten Çıkarılması Gerekenler
- Flutter web, Dart kodunu CanvasKit/Skwasm (WebAssembly tabanlı Skia) ile bir
<canvas>üzerine çizer — eski HTML renderer kaldırıldı, artık render motoru seçimi gerekmiyor. dart:io, web'de çalışmaz — platforma göre farklı dosyaların derlenmesini sağlayan koşullu import (if (dart.library.html) '...') ile çözülür.kIsWeb, aynı dosya içinde çalışma zamanı platform kontrolü için kullanılır; koşullu import, derleme zamanı kararı verir.- Masaüstü, native bir uygulama olarak derlenir (
dart:ioçalışır);MouseRegion(hover),Shortcuts/Actions(klavye kısayolları) gibi mobilde anlamsız etkileşim kalıpları burada gereklidir. window_manager, pencere boyutu/konumu gibi Flutter'ın yerleşik sunmadığı masaüstü özelliklerini sağlar.- Web/masaüstünde, responsive tasarım (Bölüm 4 Konu 17) isteğe bağlı değil, zorunludur.
📝 Ödevler
- [ ] Mevcut bir mobil projeni
flutter run -d chromeile web'de çalıştır, hangi widget'ların/layout'ların beklenmedik göründüğünü tespit et. - [ ]
dart:iokullanan bir paket eklediğinde web build'inin neden hata verdiğini gözlemle, koşullu import ile bir çözüm tasarla (elle uygulamana gerek yok, tasarımını yaz). - [ ]
kIsWebkullanarak, web'de farklı davranan (örn. farklı bir buton metni gösteren) basit bir widget yaz. - [ ] (Masaüstünde çalışıyorsan)
MouseRegionile hover'da renk değiştiren bir kart,Shortcuts/Actionsile birCtrl+Skısayolu ekle. - [ ] Kendi cümlelerinle, "Flutter web'in neden normal bir HTML sayfası gibi değil, bir
<canvas>'a çizilmiş bir resim gibi düşünülmesi gerektiğini" açıkla.
Sıradaki konu: Bölüm 12 — Konu 56: Custom RenderObject Yazımı