Router (router) — architectuurpatroon dat de navigatielogica tussen applicatieschermen centraliseert. Router bepaalt waar en hoe naartoe te gaan bij een gebeurtenis. In iOS abstraheert Router UINavigationController en segue, in Android — FragmentManager en NavController van Jetpack Navigation. Router kan als zelfstandig patroon werken of als component van Coordinator (Router-per-Coordinator) en VIPER (Router-per-module). Meer — in Android Navigation Component Guide.
Belangrijkste punten
Router — patroon dat de logica van schermovergangen inkapselt. Hoofdidee: ViewController (of Presenter/ViewModel) roept niet direct navigationController.pushViewController aan, maar meldt Router de intentie om te navigeren. Router beslist welke ViewController te maken en hoe weer te geven. Router kan eenvoudig zijn (verzameling navigatiemethoden) of complex (met routering via URL-schema's, deep links en pushmeldingen).
Drie benaderingen van Router — Router als service (globale Navigator-singleton), Router als modulcomponent (VIPER-benadering), Router als protocol (abstractie voor Coordinator). Globale Router — eenvoud (één instantie per applicatie) — populair in kleine projecten. Modulaire Router — elke functie heeft eigen Router — standaard van VIPER en Clean Architecture. Protocol-Router — gebruikt in Coordinator: RouterProtocol met push/present/pop/dismiss-methoden.
| Benadering | Structuur | Wanneer gebruiken |
|---|---|---|
| Globale Navigator | Singleton met overgangsmethoden | Kleine projecten, prototypes |
| Modulaire Router | Router in elke module | VIPER, Clean Architecture |
| Protocol-Router | Protocol + implementatie voor Coordinator | MVVM-C, Coordinator-patroon |
Geschiedenis van het patroon — Router verscheen in webframeworks (URL Router — Rails Routes, Express.js) en werd aangepast voor mobiele ontwikkeling. In iOS werd Router populair met de groei van VIPER (2015-2017). In Android — Router als onderdeel van Jetpack Navigation (2018), Google's standaardoplossing voor navigatie. Nu is Router een onlosmakelijk onderdeel van elke modulaire architectuur van mobiele applicaties.
iOS Router — protocol met methoden voor verschillende navigatietypen. De basisimplementatie omhult UINavigationController. Router kan modale presentaties (present/dismiss), push/pop in de navigatiestack, showDetail voor Split View Controller en volledige-scherm presentaties (iOS 13+) beheren. Router maakt geen ViewController — hij ontvangt een kant-en-klaar exemplaar en toont het. Het maken van ViewController wordt gedaan door een fabriek (Assembly, DI-container) of Coordinator.
// RouterProtocol voor 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)
}
// Implementatie van Router via 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 — aanmaken van module met Router
protocol ProfileModuleFactory {
func makeProfileView() -> UIViewController
}
Router in VIPER — elke VIPER-module heeft zijn eigen Router die weet welke schermen te openen vanuit de huidige module. Router maakt de ViewController van de volgende module via een fabriek en draagt controle over. Router in VIPER — enige component die import UIKit bevat (behalve View). Dit vereenvoudigt het testen van Presenter en Interactor: ze zijn niet afhankelijk van UIKit.
Jetpack Navigation Component — standaardrouter voor Android, aanbevolen door Google sinds 2018. Navigatie wordt gedefinieerd in een XML-grafiek (nav_graph.xml): knooppunten (fragments, activities, destinations) en randen (actions). NavController beheert overgangen: roept FragmentManager.replace/add aan en beheert de back-stack. Navigation Component ondersteunt deep links, argumenten, overgangsanimaties en Safe Args voor typeveilige gegevensoverdracht.
// nav_graph.xml — navigatiegraaf
<!-- @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 — navigatie via 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 — typeveilige argumenten
class HomeFragmentArgs : NavArgs {
val userId: Int get() = arguments?.getInt("userId") ?: 0
}
// NavigationUI — integratie met 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 — Navigation Component ondersteunt expliciete deep links (PendingIntent + NavDeepLinkBuilder) en impliciete (via intent-filter in manifest). Deep link kan naar elk knooppunt in nav_graph leiden. Verwerking van pushmeldingen: Notification maakt een PendingIntent met NavDeepLinkBuilder die de back-stack herstelt en het gewenste scherm opent. Navigation Component verwerkt automatisch Up/Back-knoppen en brengt de gebruiker terug naar het vorige scherm.
URL Routing — routering op basis van URL-schema's, deep links en universal links. De applicatie registreert een schema (myapp://profile/42) of een universal link (https://example.com/profile/42). Router parseert de URL, extraheert parameters (userId=42) en opent het bijbehorende scherm. URL Routing maakt het mogelijk de app extern te openen: via een link van een website, e-mail, pushmelding, QR-code. iOS gebruikt NSUserActivity + universal link, Android — intent-filter + deep link.
// URL Router — parsen van deep link en navigatie
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 — toewijzen van URL aan routes
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 de praktijk — de app moet deep links verwerken in drie toestanden: niet gestart (opstarten met deep link), op de achtergrond (herstel uit achtergrond), actief (onNewIntent/SceneDelegate). URL Router moet de back-stack correct herstellen: bij een deep link naar het profielscherm moet de gebruiker op Back kunnen drukken en terugkeren naar het vorige scherm. iOS en Android verwerken de back-stack verschillend — Router moet platformkenmerken in acht nemen.
Router vs Coordinator — Router beantwoordt de vraag "hoe het scherm tonen?" (push/present), Coordinator — "welk scherm tonen?" (welke flow te starten). Router — navigatie-instrument, Coordinator — flow-organisator. Router wordt gebruikt door Coordinator. In VIPER vervult Router beide functies: beslissen waarheen te gaan en hoe te tonen. In MVVM-C is Router — een apart protocol gebruikt door Coordinator. Patronen sluiten elkaar niet uit, maar vullen elkaar aan.
| Kenmerk | Router | Coordinator | Navigator |
|---|---|---|---|
| Focus | Navigatiemechanica | Navigatie-flow | Globale toegang |
| Niveau | UI-framework (push/present) | Bedrijfslogica (flow) | Infrastructuur |
| Schermcreatie | Ontvangt kant-en-klare VC | Maakt VC via fabriek | Maakt VC |
| Levenscyclus | Eén per navigatie | childCoordinators | Singleton |
Router vs Navigator — Navigator — verouderde naam voor Router in de iOS-gemeenschap. In vroege implementaties was Navigator een Singleton-klasse met overgangsmethoden. Navigator — een globale Router-singleton. Navigator is eenvoudiger, maar creëert verborgen afhankelijkheden. Router op protocollen — beter testbaar en modulairder. Navigator is geschikt voor projecten zonder strikte architectuur, Router — voor Clean Architecture en VIPER.
Veelgestelde vragen
Router — abstractie boven UINavigationController (push/present/pop). Coordinator — laag boven Router die de flow beheert (welk scherm als volgende te tonen). Router is verantwoordelijk voor de mechanica, Coordinator — voor de navigatielogica. Coordinator gebruikt Router om overgangen uit te voeren. In VIPER combineert Router beide functies, in MVVM-C zijn ze gescheiden.
Nee. Voor apps met 3-5 schermen zijn directe aanroepen van navigationController.pushViewController een normale oplossing. Router wordt nuttig bij 10+ schermen, deep links, pushmeldingen en modulaire architectuur. Router vereenvoudigt het testen van navigatie en maakt gecentraliseerde verwerking van overgangen vanuit elke bron (knop, deep link, push) mogelijk.
URL Router — uitbreiding van Router die deep links en universal links parseert. URL Router bepaalt de overeenkomst tussen URL en app-scherm. Bijvoorbeeld, route myapp://profile/42 → ProfileViewController(userId: 42). URL Router centraliseert de verwerking van deep links uit verschillende bronnen: pushmeldingen, QR-codes, e-maillinks, universele links.
Ja. Router kan zelfstandig werken — als globale Navigator of als component van een VIPER-module. Router zonder Coordinator — slechts inkapseling van UINavigationController achter een protocol. Coordinator zonder Router — moeilijker (ViewController roept zelf push/present aan), maar mogelijk. Beste praktijk — Router + Coordinator samen.
Functioneel — ja, beide centraliseren navigatie. Implementatie verschilt: iOS Router — protocol + klasse rond UINavigationController; Android — Jetpack Navigation Component met XML-grafiek en NavController. Android Router is ingebouwd in het framework (Navigation Component), iOS Router — externe implementatie. Android Router ondersteunt Safe Args, iOS Router — niet (generics of Codable nodig).
Samenvatting
We ontwikkelen een mobiele applicatie turnkey
IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.
Lees ook