Router — основи патерну маршрутизації в iOS та Android

Автор: IT Sectr Опубліковано: 2026-02-19 Час читання: 9 хв

Router (маршрутизатор) — архітектурний патерн, який централізує логіку навігації між екранами застосунку. Router визначає, куди і як перейти при настанні події. В iOS Router абстрагує UINavigationController та segue, в Android — FragmentManager та NavController від Jetpack Navigation. Router може працювати як самостійний патерн або як компонент Coordinator (Router-per-Coordinator) та VIPER (Router-per-module). Докладніше — у Android Navigation Component Guide.

Головне

  • Router — патерн маршрутизації, який централізує навігацію між екранами
  • Два рівні — Router може бути компонентом Coordinator або самостійним патерном
  • iOS Router — абстракція над UINavigationController з методами push/present/pop
  • Android Router — Jetpack Navigation Component з NavController та deep links
  • URL Routing — маршрутизація на основі URL-схем (deeplink, universal link)

Що таке Router: суть патерну маршрутизації

Router — патерн, який інкапсулює логіку переходу між екранами. Основна ідея: ViewController (або Presenter/ViewModel) не викликає navigationController.pushViewController безпосередньо, а повідомляє Router про намір перейти. Router вирішує, який ViewController створити і як його відобразити. Router може бути простим (набір методів для навігації) або складним (з маршрутизацією за URL-схемами, deep link'ами та push-сповіщеннями).

Три підходи до Router — Router як сервіс (глобальний Navigator-синглтон), Router як компонент модуля (VIPER-підхід), Router як протокол (абстракція для Coordinator). Глобальний Router — простота (один екземпляр на застосунок) — популярний у невеликих проєктах. Модульний Router — кожна фіча має свій Router — стандарт VIPER та Clean Architecture. Протокольний Router — використовується в Coordinator: RouterProtocol з методами push/present/pop/dismiss.

ПідхідСтруктураКоли використовувати
Глобальний NavigatorSingleton з методами переходівМалі проєкти, прототипи
Модульний RouterRouter всередині кожного модуляVIPER, Clean Architecture
Протокольний RouterProtocol + реалізація для CoordinatorMVVM-C, Coordinator pattern

Історія патерну — Router з'явився у веб-фреймворках (URL Router — Rails Routes, Express.js) і був адаптований для мобільної розробки. В iOS Router став популярним з ростом VIPER (2015-2017). В Android Router — частина Jetpack Navigation (2018), стандартного рішення Google для навігації. Зараз Router — невід'ємна частина будь-якої модульної архітектури мобільних застосунків.

Router в iOS: реалізація на Swift

iOS Router — протокол з методами для різних типів навігації. Базова реалізація обгортає UINavigationController. Router може керувати модальними презентаціями (present/dismiss), push/pop у стеку навігації, showDetail для Split View Controller та повноекранними презентаціями (iOS 13+). Router не створює ViewController — він отримує готовий екземпляр і відображає його. Створенням ViewController займається фабрика (Assembly, DI-контейнер) або Coordinator.

swift
// RouterProtocol для 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 через 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 — створення модуля з Router
protocol ProfileModuleFactory {
    func makeProfileView() -> UIViewController
}

Router у VIPER — кожен VIPER-модуль має власний Router, який знає, які екрани відкривати з поточного модуля. Router створює ViewController наступного модуля через фабрику та передає керування. Router у VIPER — єдиний компонент, який містить import UIKit (крім View). Це спрощує тестування Presenter та Interactor: вони не залежать від UIKit.

Router в Android: Jetpack Navigation Component

Jetpack Navigation Component — стандартний роутер для Android, рекомендований Google з 2018 року. Навігація визначається в XML-графі (nav_graph.xml): вузли (fragments, activities, destinations) та ребра (actions). NavController керує переходами: викликає FragmentManager.replace/add та керує стеком повернення. Navigation Component підтримує deep links, аргументи, анімації переходів та Safe Args для типобезпечної передачі даних.

kotlin
// nav_graph.xml — граф навігації
<!-- @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
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 — типобезпечні аргументи
class HomeFragmentArgs : NavArgs {
    val userId: Int get() = arguments?.getInt("userId") ?: 0
}

// NavigationUI — інтеграція з 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 в Android Navigation — Navigation Component підтримує явні deep links (PendingIntent + NavDeepLinkBuilder) та неявні (через intent-filter у маніфесті). Deep link може вести на будь-який вузол nav_graph. Обробка push-сповіщень: Notification створює PendingIntent з NavDeepLinkBuilder, який відновлює стек повернення та відкриває потрібний екран. Navigation Component автоматично обробляє кнопки Up/Back та повертає користувача на попередній екран.

URL Routing: Deeplink та Universal Link маршрутизація

URL Routing — маршрутизація на основі URL-схем, deep link'ів та universal link'ів. Застосунок реєструє схему (myapp://profile/42) або universal link (https://example.com/profile/42). Router парсить URL, витягує параметри (userId=42) та відкриває відповідний екран. URL Routing дозволяє відкривати застосунок ззовні: за посиланням з вебсайту, електронної пошти, push-сповіщення, QR-коду. iOS використовує NSUserActivity + universal link, Android — intent-filter + deep link.

swift
// URL Router — парсинг deep link та навігація
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 з маршрутами
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 маршрутизація на практиці — застосунок повинен обробляти deep link у трьох станах: не запущено (запуск з deep link), у фоні (відновлення з background), активно (onNewIntent/SceneDelegate). URL Router повинен коректно відновлювати стек повернення: при deep link на екран профілю користувач повинен мати можливість натиснути Back і повернутися на попередній екран. iOS та Android по-різному обробляють стек повернення — Router повинен враховувати платформенні особливості.

Порівняння Router з Coordinator та Navigator

Router vs Coordinator — Router відповідає на питання «як показати екран?» (push/present), Coordinator — «який екран показати?» (який flow запустити). Router — інструмент навігації, Coordinator — організатор flow. Coordinator використовує Router. У VIPER Router виконує обидві функції: вирішує, куди перейти і як показати. У MVVM-C Router — окремий протокол, який використовує Coordinator. Патерни не виключають, а доповнюють один одного.

ХарактеристикаRouterCoordinatorNavigator
ФокусМеханіка навігаціїFlow навігаціїГлобальний доступ
РівеньUI-фреймворк (push/present)Бізнес-логіка (flow)Інфраструктура
Створення екранівОтримує готовий VCСтворює VC через фабрикуСтворює VC
Життєвий циклОдин на навігаціюchildCoordinatorsSingleton

Router vs Navigator — Navigator — старіша назва Router в iOS-спільноті. У ранніх реалізаціях Navigator був Singleton-класом з методами переходів. Navigator — це глобальний Router-синглтон. Navigator простіший, але створює приховані залежності. Router на протоколах — тестованіший і модульніший. Navigator підходить для проєктів без суворої архітектури, Router — для Clean Architecture та VIPER.

Часті запитання

У чому різниця між Router та Coordinator?

Router — абстракція над UINavigationController (push/present/pop). Coordinator — шар над Router, який керує flow (який екран показати наступним). Router відповідає за механіку, Coordinator — за логіку навігації. Coordinator використовує Router для виконання переходів. У VIPER Router поєднує обидві функції, у MVVM-C — розділені.

Чи обов'язково використовувати Router у мобільному застосунку?

Ні. Для застосунків з 3-5 екранами прямі виклики navigationController.pushViewController — нормальне рішення. Router стає корисним при 10+ екранах, deep link'ах, push-сповіщеннях та модульній архітектурі. Router спрощує тестування навігації та дозволяє централізовано обробляти переходи з будь-якого джерела (кнопка, deep link, push-сповіщення).

Як Router пов'язаний з Deep Links?

URL Router — розширення Router, яке парсить deep link'и та universal link'и. URL Router визначає відповідність між URL та екраном застосунку. Наприклад, маршрут myapp://profile/42 → ProfileViewController(userId: 42). URL Router централізує обробку deep link'ів з різних джерел: push-сповіщення, QR-коди, посилання в email, універсальні посилання.

Чи можна використовувати Router без Coordinator?

Так. Router може працювати самостійно — як глобальний Navigator або як компонент VIPER модуля. Router без Coordinator — це просто інкапсуляція UINavigationController за протоколом. Coordinator без Router — складніше (ViewController сам викликає push/present), але можливо. Найкраща практика — Router + Coordinator разом.

Router в Android — це те саме, що iOS Router?

Функціонально — так, обидва централізують навігацію. Реалізація різна: iOS Router — протокол + клас навколо UINavigationController; Android — Jetpack Navigation Component з XML-графом та NavController. Android Router вбудований у фреймворк (Navigation Component), iOS Router — стороння імплементація. Android Router підтримує Safe Args, iOS Router — ні (потрібні generics або Codable).

Підсумки

  • Router — патерн маршрутизації, який інкапсулює логіку переходів між екранами
  • iOS Router — протокол з методами push/present/pop навколо UINavigationController
  • Android Router — Jetpack Navigation Component з XML nav_graph та NavController
  • URL Routing — маршрутизація за deep link'ами та універсальними посиланнями
  • Router vs Coordinator — Router відповідає за механіку, Coordinator за flow навігації
  • Застосування — модульна архітектура, deep link'и, тестування навігації

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також