Router (Router) — ein Architekturmuster, das die Navigationslogik zwischen App-Bildschirmen zentralisiert. Der Router bestimmt, wohin und wie navigiert werden soll, wenn ein Ereignis eintritt. In iOS abstrahiert der Router UINavigationController und Segue, in Android — FragmentManager und NavController von Jetpack Navigation. Der Router kann als eigenständiges Muster oder als Komponente von Coordinator (Router-per-Coordinator) und VIPER (Router-per-module) arbeiten. Mehr Details — im Android Navigation Component Guide.
Wichtige Punkte
Router — ein Muster, das die Logik der Übergänge zwischen Bildschirmen kapselt. Die Grundidee: ViewController (oder Presenter/ViewModel) ruft nicht direkt navigationController.pushViewController auf, sondern teilt dem Router die Absicht zur Navigation mit. Der Router entscheidet, welcher ViewController erstellt und wie er angezeigt wird. Der Router kann einfach (eine Reihe von Navigationsmethoden) oder komplex (mit URL-Schema-Routing, Deep Links und Push-Benachrichtigungen) sein.
Drei Ansätze für Router — Router als Dienst (globaler Navigator-Singleton), Router als Modulkomponente (VIPER-Ansatz), Router als Protokoll (Abstraktion für Coordinator). Globaler Router — Einfachheit (eine Instanz pro App) — beliebt in kleinen Projekten. Modularer Router — jede Funktion hat ihren eigenen Router — VIPER- und Clean-Architecture-Standard. Protokoll-Router — verwendet in Coordinator: RouterProtocol mit push/present/pop/dismiss-Methoden.
| Ansatz | Struktur | Wann verwenden |
|---|---|---|
| Globaler Navigator | Singleton mit Navigationsmethoden | Kleine Projekte, Prototypen |
| Modularer Router | Router in jedem Modul | VIPER, Clean Architecture |
| Protokoll-Router | Protokoll + Implementierung für Coordinator | MVVM-C, Coordinator-Muster |
Geschichte des Musters — Der Router erschien in Web-Frameworks (URL Router — Rails Routes, Express.js) und wurde für die mobile Entwicklung adaptiert. In iOS wurde der Router mit dem Aufstieg von VIPER (2015-2017) populär. In Android ist der Router Teil von Jetpack Navigation (2018), Googles Standard-Navigationslösung. Heute ist der Router ein integraler Bestandteil jeder modularen mobilen App-Architektur.
iOS Router — ein Protokoll mit Methoden für verschiedene Navigationstypen. Die Basisimplementierung kapselt UINavigationController. Der Router kann modale Präsentationen (present/dismiss), Push/Pop im Navigationsstapel, showDetail für Split View Controller und Vollbild-Präsentationen (iOS 13+) verarbeiten. Der Router erstellt keine ViewControllers — er empfängt eine fertige Instanz und zeigt sie an. Die ViewController-Erstellung erfolgt durch eine Factory (Assembly, DI-Container) oder Coordinator.
// RouterProtocol für iOS
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)
}
// Router-Implementierung über UINavigationController
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 — Erstellen eines Moduls mit Router
protocol ProfileModuleFactory {
func makeProfileView() -> UIViewController
}
Router in VIPER — jedes VIPER-Modul hat seinen eigenen Router, der weiß, welche Bildschirme vom aktuellen Modul aus geöffnet werden können. Der Router erstellt den ViewController des nächsten Moduls über eine Factory und übergibt die Kontrolle. Der Router in VIPER ist die einzige Komponente, die import UIKit enthält (außer View). Dies vereinfacht das Testen von Presenter und Interactor: Sie sind nicht von UIKit abhängig.
Jetpack Navigation Component — der Standard-Router für Android, von Google seit 2018 empfohlen. Die Navigation wird in einem XML-Graphen (nav_graph.xml) definiert: Knoten (Fragments, Activities, Destinations) und Kanten (Actions). NavController verwaltet die Übergänge: ruft FragmentManager.replace/add auf und verwaltet den Rückwärtsstapel. Die Navigation Component unterstützt Deep Links, Argumente, Übergangsanimationen und Safe Args für typsichere Datenübergabe.
// nav_graph.xml — Navigationsgraph
<!-- @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 — Navigation über NavController
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 — typsichere Argumente
class HomeFragmentArgs : NavArgs {
val userId: Int get() = arguments?.getInt("userId") ?: 0
}
// NavigationUI — Integration mit Toolbar, BottomNav, Drawer
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)
}
}
Deep Links in Android Navigation — die Navigation Component unterstützt explizite Deep Links (PendingIntent + NavDeepLinkBuilder) und implizite (über Intent-Filter im Manifest). Ein Deep Link kann zu jedem Knoten des nav_graph führen. Push-Benachrichtigungsverarbeitung: Die Notification erstellt einen PendingIntent mit NavDeepLinkBuilder, der den Rückwärtsstapel wiederherstellt und den gewünschten Bildschirm öffnet. Die Navigation Component verarbeitet automatisch Up/Back-Tasten und führt den Benutzer zum vorherigen Bildschirm zurück.
URL Routing — Routing basierend auf URL-Schemata, Deep Links und Universal Links. Die App registriert ein Schema (myapp://profile/42) oder einen Universal Link (https://example.com/profile/42). Der Router parst die URL, extrahiert Parameter (userId=42) und öffnet den entsprechenden Bildschirm. URL Routing ermöglicht das Öffnen der App von außen: über einen Link von einer Website, E-Mail, Push-Benachrichtigung, QR-Code. iOS verwendet NSUserActivity + Universal Link, Android — Intent-Filter + Deep Link.
// URL Router — Deep-Link-Parsing und Navigation
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 — Zuordnung von URLs zu Routen
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
}
}
}
}
Deep-Link-Routing in der Praxis — die App muss Deep Links in drei Zuständen verarbeiten: nicht gestartet (Start mit Deep Link), im Hintergrund (Wiederherstellung aus dem Hintergrund), aktiv (onNewIntent/SceneDelegate). Der URL Router muss den Rückwärtsstapel korrekt wiederherstellen: Bei einem Deep Link zu einem Profilbildschirm sollte der Benutzer die Zurück-Taste drücken können, um zum vorherigen Bildschirm zurückzukehren. iOS und Android verarbeiten Rückwärtsstapel unterschiedlich — der Router muss plattformspezifische Besonderheiten berücksichtigen.
Router vs Coordinator — der Router beantwortet die Frage „Wie zeige ich einen Bildschirm?" (push/present), der Coordinator — „Welchen Bildschirm zeige ich?" (welcher Flow gestartet wird). Der Router ist ein Navigationswerkzeug, der Coordinator ein Flow-Organisator. Der Coordinator verwendet den Router. In VIPER übernimmt der Router beide Funktionen: entscheidet, wohin und wie angezeigt wird. In MVVM-C ist der Router ein separates Protokoll, das vom Coordinator verwendet wird. Die Muster schließen sich nicht aus, sondern ergänzen sich.
| Eigenschaft | Router | Coordinator | Navigator |
|---|---|---|---|
| Fokus | Navigationsmechanik | Navigationsflow | Globaler Zugriff |
| Ebene | UI-Framework (push/present) | Geschäftslogik (Flow) | Infrastruktur |
| Bildschirmerstellung | Empfängt fertigen VC | Erstellt VC über Factory | Erstellt VC |
| Lebenszyklus | Einer pro Navigation | childCoordinators | Singleton |
Router vs Navigator — Navigator ist ein älterer Name für Router in der iOS-Community. In frühen Implementierungen war Navigator eine Singleton-Klasse mit Navigationsmethoden. Navigator ist ein globaler Router-Singleton. Navigator ist einfacher, erzeugt aber versteckte Abhängigkeiten. Der protokollbasierte Router ist testbarer und modularer. Navigator eignet sich für Projekte ohne strenge Architektur, Router — für Clean Architecture und VIPER.
Häufig gestellte Fragen
Router ist eine Abstraktion über UINavigationController (push/present/pop). Coordinator ist eine Schicht über dem Router, die den Flow verwaltet (welcher Bildschirm als nächster angezeigt wird). Der Router kümmert sich um die Mechanik, der Coordinator um die Navigationslogik. Der Coordinator verwendet den Router zur Durchführung von Übergängen. In VIPER vereint der Router beide Funktionen; in MVVM-C sind sie getrennt.
Nein. Für Apps mit 3-5 Bildschirmen sind direkte Aufrufe von navigationController.pushViewController eine völlig akzeptable Lösung. Der Router wird bei 10+ Bildschirmen, Deep Links, Push-Benachrichtigungen und modularer Architektur nützlich. Der Router vereinfacht das Testen der Navigation und ermöglicht die zentrale Verarbeitung von Übergängen aus jeder Quelle (Button, Deep Link, Push-Benachrichtigung).
URL Router ist eine Erweiterung des Routers, die Deep Links und Universal Links parst. Der URL Router bestimmt die Zuordnung zwischen URLs und App-Bildschirmen. Zum Beispiel: Route myapp://profile/42 → ProfileViewController(userId: 42). Der URL Router zentralisiert die Deep-Link-Verarbeitung aus verschiedenen Quellen: Push-Benachrichtigungen, QR-Codes, E-Mail-Links, Universal Links.
Ja. Der Router kann unabhängig arbeiten — als globaler Navigator oder als VIPER-Modulkomponente. Router ohne Coordinator kapselt lediglich UINavigationController hinter einem Protokoll. Coordinator ohne Router ist komplexer (ViewController ruft push/present direkt auf), aber möglich. Beste Praxis ist Router + Coordinator zusammen.
Funktional — ja, beide zentralisieren die Navigation. Die Implementierung ist unterschiedlich: iOS Router — Protokoll + Klasse um UINavigationController; Android — Jetpack Navigation Component mit XML-Graph und NavController. Android Router ist in das Framework eingebaut (Navigation Component), iOS Router ist eine Drittanbieter-Implementierung. Android Router unterstützt Safe Args, iOS Router nicht (benötigt Generics oder Codable).
Zusammenfassung
Wir entwickeln eine mobile Applikation schlüsselfertig
IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.
Lesen Sie auch