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 в navigation stack, showDetail для Split View Controller и полноэкранные presentation (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 in 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 и управляет back stack'ом. 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, который восстанавливает back stack и открывает нужный экран. 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 позволяет открывать приложение из вне: по ссылке с сайта, из email, 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 routing на практике — приложение должно обрабатывать deep link в трёх состояниях: не запущено (запуск с deep link), в фоне (восстановление из background), активно (onNewIntent/SceneDelegate). URL Router должен корректно восстанавливать back stack: при deep link на экран профиля, пользователь должен иметь возможность нажать Back и вернуться на предыдущий экран. iOS и Android по-разному обрабатывают back stack — Router должен учитывать платформенные особенности.

Сравнение Router с Coordinator и Navigator

Router vs Coordinator — Router отвечает на вопрос «как показать экран?» (push/present), Coordinator — «какой экран показать?» (какой flow запустить). Router — инструмент навигации, Coordinator — организатор flow. Router используется Coordinator'ом. В 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, пуша).

Как Router связан с Deep Links?

URL Router — расширение Router, парсящее deep link'и и universal link'и. URL Router определяет соответствие между URL и экраном приложения. Например, route 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 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

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