# Flutter Navigation 2.0 ve GoRouter 2026: Deep Linking ve Mülakat Soruları > GoRouter 17.5 ile Flutter navigasyonunda ustalaşma: deklaratif routing, deep linking, ShellRoute, route guard'lar ve pratik örneklerle mülakat soruları. - Published: 2026-08-23 - Updated: 2026-08-23 - Author: Anthony Fillion-Maillet - Tags: flutter, navigation, gorouter, deep-linking, mobile - Reading time: 9 min --- Flutter navigasyonu, Navigation 2.0'ın tanıtılmasından bu yana önemli bir evrim geçirdi. Flutter ekibinin resmi paketi olan GoRouter 17.5, Router API'nin karmaşıklığını yönetirken deklaratif routing, otomatik deep linking ve iç içe navigasyonu kutudan çıktığı gibi sunuyor. > **GoRouter özellik açısından tamamlanmış durumda** > > Flutter ekibi, GoRouter'ı 2026 itibarıyla özellik açısından tamamlanmış kabul ediyor. Path parametreleri, query parametreleri, yönlendirmeler, kalıcı UI için ShellRoute ve sekme durumunu korumak için StatefulShellRoute destekleniyor. Ham Navigator 2.0 prodüksiyonda artık nadiren elle yazılıyor. ## Navigator 2.0 Mimarisi Navigator 2.0, Flutter navigasyonuna deklaratif, URL odaklı bir yaklaşım getirdi. Zorunlu `push` ve `pop` çağrıları yerine, uygulama durumu navigasyon yığınında neyin görüneceğini belirliyor. Mimari üç temel sınıfa dayanıyor: - **Router**: Navigasyonu koordine eden üst düzey widget - **RouteInformationParser**: URL'leri uygulama durumuna çeviren bileşen - **RouterDelegate**: Bu duruma göre widget ağacını oluşturan bileşen İşletim sisteminden bir deep link geldiğinde veya web tarayıcısında URL değiştiğinde, framework durumu günceller ve UI tepki verir. Sorun şu ki, özel bir `RouterDelegate` ve `RouteInformationParser` yazmak önemli miktarda boilerplate kod gerektiriyor. ```dart // raw_navigator2_example.dart // Raw Navigator 2.0 approach - verbose and rarely used directly class AppRouterDelegate extends RouterDelegate with ChangeNotifier, PopNavigatorRouterDelegateMixin { @override final GlobalKey navigatorKey = GlobalKey(); AppRoutePath? _currentPath; @override AppRoutePath? get currentConfiguration => _currentPath; @override Widget build(BuildContext context) { return Navigator( key: navigatorKey, pages: [ const MaterialPage(child: HomeScreen()), if (_currentPath?.isProductPage == true) MaterialPage(child: ProductScreen(id: _currentPath!.productId!)), ], onDidRemovePage: (page) { // Handle page removal }, ); } @override Future setNewRoutePath(AppRoutePath path) async { _currentPath = path; notifyListeners(); } } ``` Bu uzunluk, GoRouter'ın var olma sebebi. Navigator 2.0'ı sarmalayarak tüm boilerplate'i yönetiyor. ## GoRouter 17.5 Kurulumu GoRouter 17.5, route metadata desteği ve path parametreleri için düzenli ifade kısıtlamaları getiriyor. Minimum gereksinimler Flutter 3.32 ve Dart 3.8. ```dart // router_config.dart import 'package:go_router/go_router.dart'; final goRouter = GoRouter( initialLocation: '/', debugLogDiagnostics: true, // Useful during development routes: [ GoRoute( path: '/', name: 'home', builder: (context, state) => const HomeScreen(), routes: [ GoRoute( path: 'products/:id', // Path parameter name: 'product', builder: (context, state) { final productId = state.pathParameters['id']!; return ProductScreen(productId: productId); }, ), GoRoute( path: 'search', name: 'search', builder: (context, state) { // Query parameters: /search?q=flutter&category=books final query = state.uri.queryParameters['q'] ?? ''; final category = state.uri.queryParameters['category']; return SearchScreen(query: query, category: category); }, ), ], ), ], ); ``` Router, `MaterialApp.router` ile entegre edilir: ```dart // main.dart import 'package:flutter/material.dart'; import 'router_config.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp.router( routerConfig: goRouter, title: 'GoRouter Demo', ); } } ``` ## Android ve iOS için Deep Linking Yapılandırması Deep linking, harici URL'lerin uygulamada belirli ekranları açmasına olanak tanır. Platform yapılandırması tamamlandığında GoRouter routing'i otomatik olarak yönetir. ### Android App Links Android, `AndroidManifest.xml`'de bir `intent-filter` ve domain'de barındırılan bir Digital Asset Links dosyası gerektirir: ```xml ``` `assetlinks.json` dosyası `https://example.com/.well-known/assetlinks.json` adresinde sunulmalıdır. ### iOS Universal Links iOS için Xcode'da `Associated Domains` yeteneği etkinleştirilmeli ve bir `apple-app-site-association` dosyası barındırılmalıdır: ```json // https://example.com/.well-known/apple-app-site-association { "applinks": { "apps": [], "details": [ { "appID": "TEAMID.com.example.app", "paths": ["/products/*", "/search"] } ] } } ``` GoRouter 17.5, boş path'li Android cold-start deep linklerinin scheme ve authority'yi kaybettiği kritik bir hatayı düzeltti. Bu, uygulama çalışmıyorken bile deep linklerin artık güvenilir şekilde çalıştığı anlamına geliyor. > **Deep link testi** > > Android deep linklerini `adb shell am start -a android.intent.action.VIEW -d "https://example.com/products/123"` komutuyla test edebilirsiniz. iOS için `xcrun simctl openurl booted "https://example.com/products/123"` kullanılır. ## Kalıcı Navigasyon UI için ShellRoute ShellRoute, alt route'ları `BottomNavigationBar` veya `Drawer` gibi kalıcı bir UI öğesiyle sarar. Shell, çocuklar arasında gezinirken görünür kalır. ```dart // shell_router_config.dart final goRouter = GoRouter( initialLocation: '/home', routes: [ ShellRoute( builder: (context, state, child) { return ScaffoldWithNavBar(child: child); }, routes: [ GoRoute( path: '/home', name: 'home', builder: (context, state) => const HomeTab(), ), GoRoute( path: '/explore', name: 'explore', builder: (context, state) => const ExploreTab(), ), GoRoute( path: '/profile', name: 'profile', builder: (context, state) => const ProfileTab(), ), ], ), ], ); // scaffold_with_nav_bar.dart class ScaffoldWithNavBar extends StatelessWidget { final Widget child; const ScaffoldWithNavBar({super.key, required this.child}); @override Widget build(BuildContext context) { return Scaffold( body: child, bottomNavigationBar: BottomNavigationBar( currentIndex: _calculateSelectedIndex(context), onTap: (index) => _onItemTapped(index, context), items: const [ BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'), BottomNavigationBarItem(icon: Icon(Icons.explore), label: 'Explore'), BottomNavigationBarItem(icon: Icon(Icons.person), label: 'Profile'), ], ), ); } int _calculateSelectedIndex(BuildContext context) { final location = GoRouterState.of(context).uri.toString(); if (location.startsWith('/explore')) return 1; if (location.startsWith('/profile')) return 2; return 0; } void _onItemTapped(int index, BuildContext context) { switch (index) { case 0: context.go('/home'); case 1: context.go('/explore'); case 2: context.go('/profile'); } } } ``` GoRouter 17.5, iOS geri hareketlerinin yalnızca aktif alt route yerine tüm `ShellRoute`'u pop ettiği sorunu düzeltti. ## Sekme Durumunu Korumak için StatefulShellRoute Kullanıcılar sekmeleri değiştirdiğinde, `ShellRoute` çocuğu yeniden oluşturur. `StatefulShellRoute` her dalın navigasyon yığınını korur: ```dart // stateful_shell_config.dart final goRouter = GoRouter( initialLocation: '/home', routes: [ StatefulShellRoute.indexedStack( builder: (context, state, navigationShell) { return ScaffoldWithNavBar(navigationShell: navigationShell); }, branches: [ StatefulShellBranch( routes: [ GoRoute( path: '/home', builder: (context, state) => const HomeTab(), routes: [ GoRoute( path: 'details/:id', builder: (context, state) => DetailsScreen( id: state.pathParameters['id']!, ), ), ], ), ], ), StatefulShellBranch( routes: [ GoRoute( path: '/explore', builder: (context, state) => const ExploreTab(), ), ], ), StatefulShellBranch( routes: [ GoRoute( path: '/profile', builder: (context, state) => const ProfileTab(), ), ], ), ], ), ], ); ``` Bu yapılandırmayla, kullanıcı `/home/details/42`'ye gidip Explore sekmesine geçip tekrar Home'a döndüğünde, hala detay ekranında olacaktır. ## Redirect ile Route Guard'lar Redirect'ler kimlik doğrulama kontrollerini ve koşullu navigasyonu yönetir. `redirect` callback'i her navigasyondan önce çalışır: ```dart // authenticated_router.dart final goRouter = GoRouter( initialLocation: '/', redirect: (context, state) { final isLoggedIn = AuthService.instance.isLoggedIn; final isLoggingIn = state.matchedLocation == '/login'; // Redirect to login if not authenticated if (!isLoggedIn && !isLoggingIn) { return '/login?redirect=${state.uri}'; } // Redirect away from login if already authenticated if (isLoggedIn && isLoggingIn) { final redirect = state.uri.queryParameters['redirect']; return redirect ?? '/'; } return null; // No redirect }, routes: [ GoRoute( path: '/', builder: (context, state) => const HomeScreen(), ), GoRoute( path: '/login', builder: (context, state) => const LoginScreen(), ), GoRoute( path: '/admin', redirect: (context, state) { // Route-level redirect for admin-only access if (!AuthService.instance.isAdmin) { return '/'; } return null; }, builder: (context, state) => const AdminScreen(), ), ], ); ``` GoRouter 17.5, redirect callback'leri içinde `context.namedLocation()` gibi context extension metotlarının kullanımı için destek ekledi. ## Yaygın Flutter Navigasyon Mülakat Soruları Mülakatçılar sıklıkla navigasyon bilgisini test eder çünkü bu konu mimari, durum yönetimi ve platform entegrasyonuna değinir. İşte deneyimli adayları ayırt eden sorular: **S: Navigator 2.0, Navigator 1.0'ın çözemediği hangi sorunu çözüyor?** Navigator 1.0 zorunlu navigasyon kullanır: `Navigator.push()` ve `Navigator.pop()`. Uygulama, navigasyon durumunu URL olarak temsil edemez, bu da deep linking ve web desteğini zorlaştırır. Navigator 2.0 deklaratiftir: uygulama durumu navigasyon yığınını belirler, URL'ler birinci sınıf vatandaşlardır ve deep linkler otomatik çalışır. **S: `context.go()` ile `context.push()` ne zaman kullanılır?** `context.go('/path')` mevcut navigasyon yığınını eşleşen route'a kadar değiştirir. `context.push('/path')` mevcut yığının üstüne yeni bir route ekler. `go()` üst düzey navigasyon için (sekme değiştirme, ana sayfaya gitme), `push()` ise geri navigasyonu koruyarak detaylara inmek için kullanılır. **S: Sekme geçişleri arasında durum nasıl korunur?** `StatefulShellRoute.indexedStack()` kullanılır. Her dal için ayrı navigasyon yığınları tutar ve sekme değiştirildiğinde bunları korur. Kullanılmadığında, sekme değişimi tüm alt ağacı yeniden oluşturur. **S: Route'lar arasında karmaşık nesneler nasıl geçirilir?** Üç yaklaşım mevcuttur. Birincisi, path parametresinde ID geçirip hedef ekranda nesneyi fetch etmek. İkincisi, GoRouter'ın `extra` parametresini kullanarak nesneyi doğrudan geçirmek. Üçüncüsü, nesneyi bir durum yönetimi çözümünde (Riverpod, Bloc) depolayıp hedeften erişmek. İlk yaklaşım deep linking için en iyisidir çünkü URL paylaşılabilir kalır. ```dart // Passing via extra (not deep-linkable) context.push('/product', extra: productObject); // Receiving via extra GoRoute( path: '/product', builder: (context, state) { final product = state.extra as Product?; return ProductScreen(product: product); }, ), ``` **S: GoRouter 17.5'teki `onEnter` callback nedir?** `onEnter` callback'i bir route'a girildiğinde çalışır ve hem mevcut hem de sonraki route durumlarına erişim sağlar. Route tam yüklenmeden önce mantık çalıştırmaya olanak tanır, analitik veya koşullu ön yükleme için kullanışlıdır. ## Kod Üretimi ile Tip-Güvenli Route'lar GoRouter, kod üretimi aracılığıyla tip-güvenli routing'i destekler. Route veri sınıfları tanımlanır ve `build_runner` navigasyon kodunu üretir: ```dart // routes.dart import 'package:go_router/go_router.dart'; part 'routes.g.dart'; @TypedGoRoute(path: '/') class HomeRoute extends GoRouteData { const HomeRoute(); @override Widget build(BuildContext context, GoRouterState state) => const HomeScreen(); } @TypedGoRoute(path: '/product/:id') class ProductRoute extends GoRouteData { final String id; const ProductRoute({required this.id}); @override Widget build(BuildContext context, GoRouterState state) => ProductScreen(productId: id); } ``` `dart run build_runner build` çalıştırıldıktan sonra, derleme zamanı güvenliği ile navigasyon yapılabilir: ```dart // Type-safe navigation ProductRoute(id: '123').go(context); ``` Bu, route path'lerindeki yazım hatalarını ortadan kaldırır ve parametrelerin her zaman sağlandığını garanti eder. ## Prodüksiyon Uygulamalarında Flutter Navigasyonunda Ustalaşma - GoRouter 17.5, deep linking, iç içe navigasyon veya web desteği gerektiren Flutter uygulamaları için önerilen navigasyon çözümüdür - Kalıcı alt navigasyon çubukları için `ShellRoute` kullanılır; her sekmenin navigasyon yığınını korumak için `StatefulShellRoute` kullanılır - Platforma özgü deep linking yapılandırması (Android App Links, iOS Universal Links) routing mantığını yöneten GoRouter'dan ayrı tutulur - Kimlik doğrulama guard'ları router seviyesinde veya bireysel route seviyesinde `redirect` callback'i ile uygulanır - Mülakat senaryolarında deklaratif modeli açıklamaya odaklanılmalıdır: uygulama durumu UI'ı yönlendirir, URL'ler durumdan türetilir ve GoRouter çeviriyi yönetir - Kod üretimi ile tip-güvenli route'lar, yanlış yazılmış path'lerden kaynaklanan runtime hatalarını ortadan kaldırır - Sürüme özgü özellikler için [Flutter navigasyon dokümantasyonu](https://docs.flutter.dev/ui/navigation) ve [GoRouter changelog](https://pub.dev/packages/go_router/changelog) kontrol edilmelidir --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/tr/blog/flutter/flutter-navigation-gorouter-deep-linking-2026