↑↓ seç · Enter aç · Esc kapat

Mutlu Tekin
Mutlu Tekin
← Yazılar

Bölüm 7 — Konu 31: Deep Linking

4 dk okuma #flutter
Dizi · 31/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. Deep Linking Nedir?
  2. İki Temel Deep Link Türü
  3. 1. Custom URL Scheme (Özel URL Şeması)
  4. 2. Universal Links (iOS) / App Links (Android)
  5. Flutter'da Kurulum — Kavramsal Bakış
  6. go_router ile Deep Link'i Karşılama
  7. Uygulama Çalışırken Gelen Bir Deep Link — Dinleme
  8. Deep Linking + State Management — Bölüm 6'ya Bağlantı
  9. URL Stratejisi — Web'de "#" (Hash) mi, Yoksa "Path" mi?
  10. 🎯 Bu Dersten Çıkarılması Gerekenler
  11. 📝 Ödevler

Deep Linking Nedir?

Deep linking, uygulamanın dışından (bir web sitesi, bir push bildirimi, başka bir uygulama) gelen bir bağlantının, uygulamayı doğrudan belirli bir ekrana açmasıdır. Bölüm 7 Konu 29-30'da öğrendiğimiz bildirimsel navigasyon (go_router), bu özelliği temelde destekleyecek şekilde tasarlanmıştır — şimdi bunu gerçekten etkinleştirmeyi öğreneceğiz.

Somut örnekler:

  • Bir e-posta bildiriminde "Siparişini Görüntüle" bağlantısına tıklandığında, uygulama doğrudan o siparişin detay ekranını açar.
  • Bir arkadaşın paylaştığı bir ürün linkine tıklandığında, uygulama o ürünün sayfasında açılır.
  • Bir web sayfasında "Uygulamada Aç" butonuna basıldığında, cihazda kurulu olan uygulama doğrudan ilgili içerikle açılır.

1. Custom URL Scheme (Özel URL Şeması)

metin
myapp://urun/123

Bu, https:// yerine kendi tanımladığın bir "şema" (myapp://) kullanır. Basit ve eski bir yöntemdir, ama sınırlamaları vardır — eğer uygulama kurulu değilse, tarayıcı genelde hata verir (çünkü myapp:// diye bir protokolü tanımaz).

metin
https://benimuygulamam.com/urun/123

Bu, gerçek bir HTTPS URL'sidir — eğer uygulama kuruluysa, işletim sistemi bunu otomatik olarak uygulamada açar; kurulu değilse, normal bir web sayfası olarak tarayıcıda açılır (bu web sayfası, App Store/Play Store'a yönlendirebilir). Bu, modern ve önerilen yaklaşımdır.

Flutter'da Kurulum — Kavramsal Bakış

Deep linking'in platform tarafı kurulumu (Android/iOS native yapılandırması), Bölüm 1 Konu 3'te öğrendiğimiz android/ ve ios/ klasörlerinde yapılır — bunlar, günlük geliştirmede nadiren dokunduğumuz ama var olduğunu bildiğimiz klasörlerdi, hatırlarsan.

Android tarafında (android/app/src/main/AndroidManifest.xml):

xml
<intent-filter android:autoVerify="true">
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data android:scheme="https" android:host="benimuygulamam.com" />
</intent-filter>

iOS tarafında (ios/Runner/Info.plist ve Apple Developer hesabı ayarları):

  • Associated Domains yapılandırması gerekir.

Bu native yapılandırmaların detaylarına girmiyoruz (bu, platform-spesifik bir konu ve resmi Flutter dokümantasyonunda güncel adımlarla takip edilmelidir) — önemli olan kavramsal olarak ne yaptıklarını anlamak: işletim sistemine, "bu domain'den gelen linkleri, benim uygulamamla aç" diye bildiriyorsun.

Bölüm 7 Konu 30'da kurduğumuz GoRoute yapısı, aslında deep linking için zaten hazırdır:

dart
final _router = GoRouter(
  routes: [
    GoRoute(path: '/', builder: (context, state) => AnaEkran()),
    GoRoute(
      path: '/urun/:id',
      builder: (context, state) => UrunDetayEkrani(urunId: state.pathParameters['id']!),
    ),
  ],
);

Eğer bir kullanıcı, https://benimuygulamam.com/urun/123 linkine tıklarsa (native yapılandırma doğru yapıldığında), işletim sistemi uygulamayı bu URL bilgisiyle başlatır, ve go_router, Bölüm 7 Konu 29'da öğrendiğimiz RouteInformationParser mekanizmasını (arka planda, senin görmeden) kullanarak, bu URL'yi doğrudan /urun/:id rotasıyla eşleştirip, UrunDetayEkrani'ni açar. Sen hiçbir ek kod yazmadan, sadece rotanı tanımlayarak, deep linking desteğine sahip oluyorsun — bu, go_router'ın en büyük pratik avantajlarından biridir.

Uygulama zaten açıkken bir deep link tetiklenirse (örneğin başka bir uygulamadan paylaşılan bir link), bunu dinlemek için app_links gibi bir paket kullanılabilir:

bash
flutter pub add app_links
dart
import 'package:app_links/app_links.dart';

class DeepLinkDinleyici {
  final _appLinks = AppLinks();

  void dinlemeyeBasla(GoRouter router) {
    _appLinks.uriLinkStream.listen((uri) { // Dart Bölüm 10'u hatırla — Stream!
      router.go(uri.path);
    });
  }
}

uriLinkStream — Dart Bölüm 10 Konu 47'de öğrendiğimiz Stream kavramının gerçek bir kullanım alanı! Uygulama açıkken gelen her yeni deep link, bu stream'e bir "olay" olarak akar — .listen() ile (Dart Bölüm 10'u hatırla), her yeni link geldiğinde router.go(uri.path) ile anlık olarak o ekrana geçiş yapılır.

Deep Linking + State Management — Bölüm 6'ya Bağlantı

Gerçek bir uygulamada, deep link ile açılan bir ekran, genelde belirli bir veriye ihtiyaç duyar (örneğin ürün detayı için, o ürünün bilgisini bir API'den çekmek gerekir — Bölüm 5'i hatırla). Bu, Bölüm 6'da öğrendiğimiz state management araçlarıyla doğal olarak birleşir:

dart
GoRoute(
  path: '/urun/:id',
  builder: (context, state) {
    final id = state.pathParameters['id']!;
    return UrunDetayEkrani(urunId: id); // bu widget içinde, Bölüm 5'teki FutureBuilder ile veri çekilir
  },
)

UrunDetayEkrani, Bölüm 5 Konu 20-21'de öğrendiğimiz gibi, initState() içinde id'yi kullanarak API'den veri çeker — deep link ile açılmış olması, bu akışı hiç değiştirmez, çünkü go_router, sadece doğru widget'ı doğru parametrelerle oluşturmaktan sorumludur.

URL Stratejisi — Web'de "#" (Hash) mi, Yoksa "Path" mi?

Flutter Web'de, varsayılan olarak URL'ler # (hash) içerir:

metin
https://benimuygulamam.com/#/urun/123

Bunu, daha temiz bir URL'ye çevirmek istersen:

dart
void main() {
  usePathUrlStrategy(); // go_router'dan gelen bir fonksiyon
  runApp(MyApp());
}
metin
https://benimuygulamam.com/urun/123

usePathUrlStrategy(), tarayıcının native History API'sini kullanarak, # olmadan temiz URL'ler üretir. Bu, özellikle SEO (arama motoru optimizasyonu) ve paylaşılabilirlik açısından önemlidir — ama sunucu tarafında ek bir yapılandırma (tüm yolları index.html'e yönlendirmek) gerektirir, çünkü artık sunucunun /urun/123 gibi bir yolu doğrudan tanıması beklenir.


🎯 Bu Dersten Çıkarılması Gerekenler

  • Deep linking, uygulama dışından gelen bir bağlantının, doğrudan belirli bir ekranı açmasıdır.
  • Universal Links/App Links (gerçek HTTPS URL'leri), eski Custom URL Scheme'lere göre daha modern ve güvenilir bir yaklaşımdır.
  • go_router'ın GoRoute yapısı, ek kod yazmadan deep linking'i doğal olarak destekler — arka planda RouteInformationParser'ı kullanır.
  • Uygulama çalışırken gelen deep link'ler, Stream tabanlı bir dinleyici (örn. app_links paketi) ile yakalanabilir.
  • usePathUrlStrategy(), Flutter Web'de #'siz, temiz URL'ler üretir (sunucu tarafı ek yapılandırma gerektirir).

📝 Ödevler

  • [ ] Kendi cümlelerinle, Custom URL Scheme ile Universal/App Links arasındaki farkı ve neden ikincisinin tercih edildiğini açıkla.
  • [ ] Bölüm 7 Konu 30'da kurduğun go_router yapısının, ek kod yazmadan neden deep linking'e "hazır" olduğunu açıkla.
  • [ ] app_links paketiyle (veya kavramsal olarak, Stream mantığını kullanarak), uygulama açıkken gelen bir deep link'i dinleyen bir kod taslağı yaz.
  • [ ] usePathUrlStrategy()'nin ne işe yaradığını ve neden sunucu tarafında ek yapılandırma gerektirdiğini kendi cümlelerinle açıkla.
  • [ ] Kendi uygulaman için (hayali bir senaryo), hangi ekranların deep link ile açılabilir olması gerektiğini listele (örn. ürün detayı, profil, bir kampanya sayfası).

Sıradaki konu: Bölüm 7 — Konu 32: Repository Pattern, Katmanlı Mimari (Data/Domain/Presentation)