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-singleton), 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 се появи в уеб frameworks (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 — стандартен router за Android, препоръчван от Google от 2018 г. Навигацията се дефинира в XML граф (nav_graph.xml): възли (fragments, activities, destinations) и ръбове (actions). NavController управлява преходите: извиква FragmentManager.replace/add и управлява back stack. Navigation Component поддържа deep link-ове, аргументи, анимации на преходи и 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 link-ове (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 позволява отваряне на приложението отвън: чрез линк от уебсайт, имейл, 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), на заден фон (възстановяване от заден фон), активно (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-framework (push/present)Бизнес логика (flow)Инфраструктура
Създаване на екраниПолучава готов VCСъздава VC чрез фабрикаСъздава VC
Жизнен цикълЕдин за навигацияchildCoordinatorsSingleton

Router vs Navigator — Navigator — остаряло наименование на Router в iOS общността. В ранните имплементации Navigator беше Singleton клас с методи за преход. Navigator — глобален Router-singleton. 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 и екрана на приложението. Например, route myapp://profile/42 → ProfileViewController(userId: 42). URL Router централизира обработката на deep link-ове от различни източници: push известия, QR кодове, имейл линкове, универсални линкове.

Може ли 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 е вграден в framework (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 г. Ще ви консултираме и ще предложим най-доброто решение.

Обсъдете проекта

Прочетете също