Router — podstawy wzorca routingu w iOS i Android

Autor: IT Sectr Opublikowano: 2026-02-19 Czas czytania: 9 min

Router (router) — wzorzec architektoniczny centralizujący logikę nawigacji między ekranami aplikacji. Router określa, dokąd i jak przejść po wystąpieniu zdarzenia. W iOS Router abstrahuje UINavigationController i segue, w Android — FragmentManager i NavController z Jetpack Navigation. Router może działać jako samodzielny wzorzec lub jako komponent Coordinator (Router-per-Coordinator) i VIPER (Router-per-module). Więcej — w Android Navigation Component Guide.

Najważniejsze

  • Router — wzorzec routingu centralizujący nawigację między ekranami
  • Dwa poziomy — Router może być komponentem Coordinator lub samodzielnym wzorcem
  • iOS Router — abstrakcja nad UINavigationController z metodami push/present/pop
  • Android Router — Jetpack Navigation Component z NavController i deep links
  • URL Routing — routing oparty na schematach URL (deeplink, universal link)

Czym jest Router: istota wzorca routingu

Router — wzorzec hermetyzujący logikę przejścia między ekranami. Główna idea: ViewController (lub Presenter/ViewModel) nie wywołuje bezpośrednio navigationController.pushViewController, lecz informuje Router o zamiarze przejścia. Router decyduje, który ViewController utworzyć i jak go wyświetlić. Router może być prosty (zbiór metod nawigacji) lub złożony (z routingiem według schematów URL, deep linków i powiadomień push).

Trzy podejścia do Router — Router jako usługa (globalny Navigator-singleton), Router jako komponent modułu (podejście VIPER), Router jako protokół (abstrakcja dla Coordinator). Globalny Router — prostota (jedna instancja na aplikację) — popularny w małych projektach. Modułowy Router — każda funkcja ma własny Router — standard VIPER i Clean Architecture. Protokołowy Router — używany w Coordinator: RouterProtocol z metodami push/present/pop/dismiss.

PodejścieStrukturaKiedy używać
Globalny NavigatorSingleton z metodami przejśćMałe projekty, prototypy
Modułowy RouterRouter wewnątrz każdego modułuVIPER, Clean Architecture
Protokołowy RouterProtocol + implementacja dla CoordinatorMVVM-C, Coordinator pattern

Historia wzorca — Router pojawił się w frameworkach webowych (URL Router — Rails Routes, Express.js) i został zaadaptowany do programowania mobilnego. W iOS Router stał się popularny wraz z rozwojem VIPER (2015-2017). W Android Router — część Jetpack Navigation (2018), standardowego rozwiązania Google do nawigacji. Obecnie Router — nieodłączna część każdej modułowej architektury aplikacji mobilnych.

Router w iOS: implementacja w Swift

iOS Router — protokół z metodami dla różnych typów nawigacji. Podstawowa implementacja opakowuje UINavigationController. Router może zarządzać prezentacjami modalnymi (present/dismiss), push/pop w stosie nawigacyjnym, showDetail dla Split View Controller oraz pełnoekranowymi prezentacjami (iOS 13+). Router nie tworzy ViewController — otrzymuje gotową instancję i wyświetla ją. Tworzeniem ViewController zajmuje się fabryka (Assembly, DI-kontener) lub Coordinator.

swift
// RouterProtocol dla 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)
}

// Implementacja Router przez 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 — tworzenie modułu z Router
protocol ProfileModuleFactory {
    func makeProfileView() -> UIViewController
}

Router in VIPER — każdy moduł VIPER ma własny Router, który wie, które ekrany otwierać z bieżącego modułu. Router tworzy ViewController następnego modułu przez fabrykę i przekazuje sterowanie. Router w VIPER — jedyny komponent zawierający import UIKit (oprócz View). Ułatwia to testowanie Presenter i Interactor: nie zależą one od UIKit.

Router w Android: Jetpack Navigation Component

Jetpack Navigation Component — standardowy router dla Android, zalecany przez Google od 2018 roku. Nawigacja jest definiowana w grafie XML (nav_graph.xml): węzły (fragments, activities, destinations) i krawędzie (actions). NavController zarządza przejściami: wywołuje FragmentManager.replace/add i zarządza back stackiem. Navigation Component obsługuje deep links, argumenty, animacje przejść i Safe Args do typowo bezpiecznego przesyłania danych.

kotlin
// nav_graph.xml — graf nawigacji
<!-- @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 — nawigacja przez 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 — typowo bezpieczne argumenty
class HomeFragmentArgs : NavArgs {
    val userId: Int get() = arguments?.getInt("userId") ?: 0
}

// NavigationUI — integracja z 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 w Android Navigation — Navigation Component obsługuje jawne deep links (PendingIntent + NavDeepLinkBuilder) i niejawne (przez intent-filter w manifeście). Deep link może prowadzić do dowolnego węzła nav_graph. Obsługa powiadomień push: Notification tworzy PendingIntent z NavDeepLinkBuilder, który odtwarza back stack i otwiera odpowiedni ekran. Navigation Component automatycznie obsługuje przyciski Up/Back i zwraca użytkownika do poprzedniego ekranu.

URL Routing: Deeplink i Universal Link routing

URL Routing — routing oparty na schematach URL, deep linkach i universal linkach. Aplikacja rejestruje schemat (myapp://profile/42) lub universal link (https://example.com/profile/42). Router parsuje URL, wyodrębnia parametry (userId=42) i otwiera odpowiedni ekran. URL Routing umożliwia otwieranie aplikacji z zewnątrz: przez link ze strony, z emaila, powiadomienia push, kodu QR. iOS używa NSUserActivity + universal link, Android — intent-filter + deep link.

swift
// URL Router — parsowanie deep link i nawigacja
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 — mapowanie URL na trasy
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 w praktyce — aplikacja musi obsługiwać deep link w trzech stanach: nieuruchomiona (uruchomienie z deep link), w tle (przywrócenie z tła), aktywna (onNewIntent/SceneDelegate). URL Router powinien poprawnie odtwarzać back stack: przy deep link do ekranu profilu użytkownik powinien móc nacisnąć Back i wrócić do poprzedniego ekranu. iOS i Android inaczej obsługują back stack — Router musi uwzględniać różnice platformowe.

Porównanie Router z Coordinator i Navigator

Router vs Coordinator — Router odpowiada na pytanie „jak wyświetlić ekran?” (push/present), Coordinator — „jaki ekran wyświetlić?” (jaki flow uruchomić). Router — narzędzie nawigacji, Coordinator — organizator flow. Router jest używany przez Coordinator. W VIPER Router pełni obie funkcje: decyduje, dokąd przejść i jak wyświetlić. W MVVM-C Router — osobny protokół używany przez Coordinator. Wzorce nie wykluczają się, lecz uzupełniają.

CharakterystykaRouterCoordinatorNavigator
CelMechanika nawigacjiFlow nawigacjiGlobalny dostęp
PoziomUI-framework (push/present)Logika biznesowa (flow)Infrastruktura
Tworzenie ekranówOtrzymuje gotowy VCTworzy VC przez fabrykęTworzy VC
Cykl życiaJeden na nawigacjęchildCoordinatorsSingleton

Router vs Navigator — Navigator — przestarzała nazwa Router w środowisku iOS. We wczesnych implementacjach Navigator był klasą Singleton z metodami przejść. Navigator — to globalny Router-singleton. Navigator jest prostszy, ale tworzy ukryte zależności. Router na protokołach — bardziej testowalny i modułowy. Navigator nadaje się do projektów bez ścisłej architektury, Router — do Clean Architecture i VIPER.

Często zadawane pytania

Jaka jest różnica między Router a Coordinator?

Router — abstrakcja nad UINavigationController (push/present/pop). Coordinator — warstwa nad Router, zarządzająca flow (jaki ekran wyświetlić jako następny). Router odpowiada za mechanikę, Coordinator — za logikę nawigacji. Coordinator używa Router do wykonywania przejść. W VIPER Router łączy obie funkcje, w MVVM-C są rozdzielone.

Czy konieczne jest używanie Router w aplikacji mobilnej?

Nie. Dla aplikacji z 3-5 ekranami bezpośrednie wywołania navigationController.pushViewController — normalne rozwiązanie. Router staje się przydatny przy 10+ ekranach, deep linkach, powiadomieniach push i architekturze modułowej. Router upraszcza testowanie nawigacji i umożliwia centralne przetwarzanie przejść z dowolnego źródła (przycisk, deep link, push).

Jak Router jest powiązany z Deep Links?

URL Router — rozszerzenie Router, parsujące deep linki i universal linki. URL Router określa dopasowanie między URL a ekranem aplikacji. Na przykład route myapp://profile/42 → ProfileViewController(userId: 42). URL Router centralizuje obsługę deep linków z różnych źródeł: powiadomienia push, kody QR, linki email, linki uniwersalne.

Czy można używać Router bez Coordinator?

Tak. Router może działać samodzielnie — jako globalny Navigator lub jako komponent modułu VIPER. Router bez Coordinator — to po prostu hermetyzacja UINavigationController za protokołem. Coordinator bez Router — trudniejszy (ViewController sam wywołuje push/present), ale możliwy. Najlepsza praktyka — Router + Coordinator razem.

Router w Android — czy to samo co iOS Router?

Funkcjonalnie — tak, oba centralizują nawigację. Implementacja różna: iOS Router — protokół + klasa wokół UINavigationController; Android — Jetpack Navigation Component z grafem XML i NavController. Android Router jest wbudowany w framework (Navigation Component), iOS Router — implementacja zewnętrzna. Android Router obsługuje Safe Args, iOS Router — nie (potrzebne generics lub Codable).

Podsumowanie

  • Router — wzorzec routingu hermetyzujący logikę przejść między ekranami
  • iOS Router — protokół z metodami push/present/pop wokół UINavigationController
  • Android Router — Jetpack Navigation Component z XML nav_graph i NavController
  • URL Routing — routing przez deep linki i uniwersalne linki
  • Router vs Coordinator — Router odpowiada za mechanikę, Coordinator za flow nawigacji
  • Zastosowanie — architektura modułowa, deep linki, testowanie nawigacji

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również