Router (yönlendirici) — uygulama ekranları arasındaki navigasyon mantığını merkezileştiren bir mimari desen. Router, bir olay gerçekleştiğinde nereye ve nasıl gidileceğini belirler. iOS'ta, Router UINavigationController ve segue'yi soyutlar; Android'de — FragmentManager ve Jetpack Navigation'dan NavController'ı. Router bağımsız bir desen olarak veya Coordinator (Router-per-Coordinator) ve VIPER (Router-per-module) bileşeni olarak çalışabilir. Daha fazla detay — Android Navigation Component Guide içinde.
Önemli Noktalar
Router — ekranlar arası geçiş mantığını kapsülleyen bir desen. Temel fikir: ViewController (veya Presenter/ViewModel) doğrudan navigationController.pushViewController'ı çağırmaz, bunun yerine Router'a navigasyon niyetini bildirir. Router hangi ViewController'ın oluşturulacağına ve nasıl görüntüleneceğine karar verir. Router basit (bir dizi navigasyon yöntemi) veya karmaşık (URL şeması yönlendirmesi, deep link'ler ve push bildirimleriyle) olabilir.
Router'a üç yaklaşım — Hizmet olarak Router (küresel Navigator singleton), Modül bileşeni olarak Router (VIPER yaklaşımı), Protokol olarak Router (Coordinator için soyutlama). Küresel Router — basitlik (uygulama başına bir örnek) — küçük projelerde popüler. Modüler Router — her özelliğin kendi Router'ı — VIPER ve Clean Architecture standardı. Protokol Router — Coordinator'da kullanılır: push/present/pop/dismiss yöntemleriyle RouterProtocol.
| Yaklaşım | Yapı | Ne Zaman Kullanılır |
|---|---|---|
| Küresel Navigator | Navigasyon yöntemleriyle Singleton | Küçük projeler, prototipler |
| Modüler Router | Her modülün içinde Router | VIPER, Clean Architecture |
| Protokol Router | Coordinator için protokol + uygulama | MVVM-C, Coordinator deseni |
Desenin tarihi — Router web çerçevelerinde (URL Router — Rails Routes, Express.js) ortaya çıktı ve mobil geliştirme için uyarlandı. iOS'ta, Router VIPER'in (2015-2017) yükselişiyle popüler hale geldi. Android'de, Router Jetpack Navigation'ın (2018) bir parçasıdır, Google'ın standart navigasyon çözümüdür. Bugün, Router herhangi bir modüler mobil uygulama mimarisinin ayrılmaz bir parçasıdır.
iOS Router — çeşitli navigasyon türleri için yöntemler içeren bir protokol. Temel uygulama UINavigationController'ı sarar. Router, kalıcı sunumları (present/dismiss), navigasyon yığınında push/pop, Split View Controller için showDetail ve tam ekran sunumları (iOS 13+) işleyebilir. Router ViewController oluşturmaz — hazır bir örnek alır ve görüntüler. ViewController oluşturma bir fabrika (Assembly, DI kabı) veya Coordinator tarafından yapılır.
// iOS için RouterProtocol
protocol RouterProtocol {
func push(_ viewController: UIViewController, animated: Bool)
func pop(animated: Bool)
func popToRoot(animated: Bool)
func present(_ viewController: UIViewController, animated: Bool)
func dismiss(animated: Bool)
func setViewControllers(_: [UIViewController], animated: Bool)
}
// UINavigationController aracılığıyla Router uygulaması
class NavigationRouter: RouterProtocol {
private let navigationController: UINavigationController
init(navigationController: UINavigationController) {
self.navigationController = navigationController
}
func push(_ vc: UIViewController, animated: Bool) {
if navigationController.presentedViewController {
navigationController.dismiss(animated: false)
}
navigationController.pushViewController(vc, animated: animated)
}
func pop(animated: Bool) {
navigationController.popViewController(animated: animated)
}
func popToRoot(animated: Bool) {
navigationController.popToRootViewController(animated: animated)
}
func present(_ vc: UIViewController, animated: Bool) {
navigationController.present(vc, animated: animated)
}
func dismiss(animated: Bool) {
navigationController.dismiss(animated: animated)
}
func setViewControllers(_ vcs: [UIViewController], animated: Bool) {
navigationController.setViewControllers(vcs, animated: animated)
}
}
// Assembly — Router ile modül oluşturma
protocol ProfileModuleFactory {
func makeProfileView() -> UIViewController
}
VIPER'da Router — her VIPER modülünün, mevcut modülden hangi ekranların açılacağını bilen kendi Router'ı vardır. Router, bir fabrika aracılığıyla sonraki modülün ViewController'ını oluşturur ve kontrolü devreder. VIPER'da Router, import UIKit içeren tek bileşendir (View hariç). Bu, Presenter ve Interactor'ın test edilmesini basitleştirir: UIKit'e bağlı değildirler.
Jetpack Navigation Component — 2018'den beri Google tarafından önerilen Android için standart yönlendirici. Navigasyon bir XML grafiğinde (nav_graph.xml) tanımlanır: düğümler (fragments, activities, destinations) ve kenarlar (actions). NavController geçişleri yönetir: FragmentManager.replace/add'i çağırır ve geri yığını yönetir. Navigation Component, deep link'leri, argümanları, geçiş animasyonlarını ve type-safe veri iletimi için Safe Args'ı destekler.
// nav_graph.xml — navigasyon grafiği
<!-- @xml/nav_graph.xml -->
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/nav_graph"
app:startDestination="@id/loginFragment">
<fragment android:id="@+id/loginFragment"
android:name=".ui.login.LoginFragment">
<action android:id="@+id/to_home"
app:destination="@id/homeFragment" />
</fragment>
<fragment android:id="@+id/homeFragment"
android:name=".ui.home.HomeFragment">
<argument android:name="userId"
android:defaultValue="0"
app:argType="integer" />
<deepLink app:uri="myapp://home/{userId}" />
</fragment>
</navigation>
// Kotlin — NavController aracılığıyla navigasyon
class LoginFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.loginButton.setOnClickListener {
val action = LoginFragmentDirections.toHome(userId = 42)
findNavController().navigate(action)
}
}
}
// Safe Args — type-safe argümanlar
class HomeFragmentArgs : NavArgs {
val userId: Int get() = arguments?.getInt("userId") ?: 0
}
// NavigationUI — Toolbar, BottomNav, Drawer ile entegrasyon
class MainActivity : AppCompatActivity() {
private lateinit var navController: NavController
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val navHost = supportFragmentManager
.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
navController = navHost.navController
NavigationUI.setupActionBarWithNavController(this, navController)
}
}
Android Navigation'da Deep link'ler — Navigation Component, açık deep link'leri (PendingIntent + NavDeepLinkBuilder) ve örtük deep link'leri (manifest'te intent-filter aracılığıyla) destekler. Bir deep link, nav_graph'ın herhangi bir düğümüne gidebilir. Push bildirimi işleme: Notification, NavDeepLinkBuilder ile bir PendingIntent oluşturur, geri yığını geri yükler ve istenen ekranı açar. Navigation Component, Up/Back düğmelerini otomatik olarak işler ve kullanıcıyı önceki ekrana döndürür.
URL Routing — URL şemalarına, deep link'lere ve universal link'lere dayalı yönlendirme. Uygulama bir şema (myapp://profile/42) veya universal link (https://example.com/profile/42) kaydeder. Router URL'yi ayrıştırır, parametreleri (userId=42) çıkarır ve ilgili ekranı açar. URL Routing, uygulamanın dışarıdan açılmasına izin verir: bir web sitesi bağlantısı, e-posta, push bildirimi, QR kodu aracılığıyla. iOS, NSUserActivity + universal link kullanır, Android — intent-filter + deep link.
// URL Router — deep link ayrıştırma ve navigasyon
protocol URLRoute {
var pattern: String { get }
func navigate(parameters: [String: String], router: RouterProtocol)
}
struct ProfileRoute: URLRoute {
let pattern = "myapp://profile/{userId}"
func navigate(parameters: [String: String], router: RouterProtocol) {
guard let userId = parameters["userId"] else { return }
let profileVC = ProfileViewController(userId: userId)
router.push(profileVC, animated: true)
}
}
// URL Router — URL'leri yollarla eşleme
class URLRouter {
private var routes: [URLRoute] = []
func handle(_ url: URL, router: RouterProtocol) {
for route in routes {
if let params = matchPattern(route.pattern, url: url) {
route.navigate(parameters: params, router: router)
return
}
}
}
}
Pratikte Deep link yönlendirme — uygulama, deep link'leri üç durumda işlemelidir: çalışmıyor (deep link ile başlatma), arka planda (arka plandan geri yükleme), aktif (onNewIntent/SceneDelegate). URL Router, geri yığını doğru şekilde geri yüklemelidir: bir profil ekranına deep link yapıldığında, kullanıcı Geri tuşuna basarak önceki ekrana dönebilmelidir. iOS ve Android geri yığınları farklı şekilde işler — Router, platforma özgü özellikleri dikkate almalıdır.
Router vs Coordinator — Router "bir ekran nasıl gösterilir?" (push/present) sorusuna yanıt verir, Coordinator — "hangi ekran gösterilir?" (hangi akış başlatılır). Router bir navigasyon aracıdır, Coordinator bir akış düzenleyicisidir. Coordinator, Router'ı kullanır. VIPER'da, Router her iki işlevi de yerine getirir: nereye gidileceğine ve nasıl gösterileceğine karar verir. MVVM-C'de, Router, Coordinator tarafından kullanılan ayrı bir protokoldür. Desenler birbirini dışlamaz, tamamlar.
| Özellik | Router | Coordinator | Navigator |
|---|---|---|---|
| Odak | Navigasyon mekaniği | Navigasyon akışı | Küresel erişim |
| Seviye | UI çerçevesi (push/present) | İş mantığı (akış) | Altyapı |
| Ekran oluşturma | Hazır VC alır | Fabrika aracılığıyla VC oluşturur | VC oluşturur |
| Yaşam döngüsü | Navigasyon başına bir | childCoordinators | Singleton |
Router vs Navigator — Navigator, iOS topluluğunda Router'ın eski bir adıdır. İlk uygulamalarda, Navigator navigasyon yöntemleri olan bir Singleton sınıfıydı. Navigator, küresel bir Router singleton'dır. Navigator daha basittir ancak gizli bağımlılıklar yaratır. Protokol tabanlı Router daha test edilebilir ve modülerdir. Navigator katı mimarisi olmayan projeler için uygundur, Router — Clean Architecture ve VIPER için.
Sıkça Sorulan Sorular
Router, UINavigationController (push/present/pop) üzerinde bir soyutlamadır. Coordinator, Router'ın üzerinde akışı (bir sonraki ekranın ne gösterileceğini) yöneten bir katmandır. Router mekaniği, Coordinator navigasyon mantığını işler. Coordinator geçişleri gerçekleştirmek için Router'ı kullanır. VIPER'da, Router her iki işlevi birleştirir; MVVM-C'de ayrılmıştır.
Hayır. 3-5 ekranlı uygulamalar için, doğrudan navigationController.pushViewController çağrıları tamamen kabul edilebilir bir çözümdür. Router, 10+ ekran, deep link'ler, push bildirimleri ve modüler mimari ile kullanışlı hale gelir. Router navigasyon testini basitleştirir ve herhangi bir kaynaktan (düğme, deep link, push bildirimi) geçişlerin merkezi olarak işlenmesini sağlar.
URL Router, deep link'leri ve universal link'leri ayrıştıran Router'ın bir uzantısıdır. URL Router, URL'ler ile uygulama ekranları arasındaki eşlemeyi belirler. Örneğin, rota myapp://profile/42 → ProfileViewController(userId: 42). URL Router, farklı kaynaklardan (push bildirimleri, QR kodları, e-posta bağlantıları, evrensel bağlantılar) deep link işlemeyi merkezileştirir.
Evet. Router bağımsız olarak çalışabilir — küresel bir Navigator veya VIPER modül bileşeni olarak. Coordinator olmadan Router, yalnızca UINavigationController'ı bir protokolün arkasına kapsüllemektir. Coordinator olmadan Router daha karmaşıktır (ViewController doğrudan push/present çağırır), ancak mümkündür. En iyi uygulama Router + Coordinator'ı birlikte kullanmaktır.
İşlevsel olarak — evet, her ikisi de navigasyonu merkezileştirir. Uygulama farklıdır: iOS Router — UINavigationController etrafında protokol + sınıf; Android — XML grafiği ve NavController ile Jetpack Navigation Component. Android Router çerçeveye (Navigation Component) yerleşiktir, iOS Router üçüncü taraf bir uygulamadır. Android Router Safe Args'ı destekler, iOS Router desteklemez (generics veya Codable gerekir).
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun