Router — fundamentos do padrão de roteamento em iOS e Android

Autor: IT Sectr Publicado: 2026-02-19 Tempo de leitura: 9 min

Router (roteador) — um padrão arquitetural que centraliza a lógica de navegação entre telas da aplicação. O Router determina para onde e como navegar quando um evento ocorre. No iOS, o Router abstrai UINavigationController e segue; no Android — FragmentManager e NavController do Jetpack Navigation. O Router pode funcionar como um padrão independente ou como um componente do Coordinator (Router-per-Coordinator) e VIPER (Router-per-module). Mais detalhes — em Android Navigation Component Guide.

Principais pontos

  • Router — padrão de roteamento que centraliza a navegação entre telas
  • Dois níveis — Router pode ser um componente do Coordinator ou um padrão independente
  • iOS Router — abstração sobre UINavigationController com métodos push/present/pop
  • Android Router — Jetpack Navigation Component com NavController e deep links
  • URL Routing — roteamento baseado em esquemas de URL (deeplink, universal link)

O que é Router: essência do padrão de roteamento

Router — um padrão que encapsula a lógica de transição entre telas. A ideia principal: ViewController (ou Presenter/ViewModel) não chama navigationController.pushViewController diretamente, mas notifica o Router sobre a intenção de navegar. O Router decide qual ViewController criar e como exibi-lo. O Router pode ser simples (um conjunto de métodos de navegação) ou complexo (com roteamento por esquemas de URL, deep links e notificações push).

Três abordagens para Router — Router como serviço (Navigator singleton global), Router como componente de módulo (abordagem VIPER), Router como protocolo (abstração para Coordinator). Router global — simplicidade (uma instância por aplicação) — popular em projetos pequenos. Router modular — cada funcionalidade tem seu próprio Router — padrão VIPER e Clean Architecture. Router de protocolo — usado no Coordinator: RouterProtocol com métodos push/present/pop/dismiss.

AbordagemEstruturaQuando usar
Navigator globalSingleton com métodos de navegaçãoProjetos pequenos, protótipos
Router modularRouter dentro de cada móduloVIPER, Clean Architecture
Router por protocoloProtocolo + implementação para CoordinatorMVVM-C, Coordinator pattern

História do padrão — Router surgiu em frameworks web (URL Router — Rails Routes, Express.js) e foi adaptado para desenvolvimento mobile. No iOS, o Router tornou-se popular com a ascensão do VIPER (2015-2017). No Android, o Router faz parte do Jetpack Navigation (2018), a solução padrão do Google para navegação. Hoje, o Router é parte integrante de qualquer arquitetura modular de aplicações móveis.

Router no iOS: implementação em Swift

iOS Router — um protocolo com métodos para vários tipos de navegação. A implementação básica envolve UINavigationController. O Router pode lidar com apresentações modais (present/dismiss), push/pop na pilha de navegação, showDetail para Split View Controller e apresentações em tela cheia (iOS 13+). O Router não cria ViewControllers — ele recebe uma instância pronta e a exibe. A criação de ViewControllers é feita por uma fábrica (Assembly, contêiner DI) ou Coordinator.

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

// Implementação de 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 — criação de um módulo com Router
protocol ProfileModuleFactory {
    func makeProfileView() -> UIViewController
}

Router no VIPER — cada módulo VIPER tem seu próprio Router, que sabe quais telas abrir a partir do módulo atual. O Router cria o ViewController do próximo módulo através de uma fábrica e passa o controle. O Router no VIPER é o único componente que contém import UIKit (exceto View). Isso simplifica os testes de Presenter e Interactor: eles não dependem do UIKit.

Router no Android: Jetpack Navigation Component

Jetpack Navigation Component — o roteador padrão para Android, recomendado pelo Google desde 2018. A navegação é definida em um grafo XML (nav_graph.xml): nós (fragments, activities, destinations) e arestas (actions). O NavController gerencia as transições: chama FragmentManager.replace/add e gerencia a pilha de retorno. O Navigation Component suporta deep links, argumentos, animações de transição e Safe Args para passagem de dados type-safe.

kotlin
// nav_graph.xml — grafo de navegação
<!-- @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 — navegação 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 — argumentos type-safe
class HomeFragmentArgs : NavArgs {
    val userId: Int get() = arguments?.getInt("userId") ?: 0
}

// NavigationUI — integração com 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 no Android Navigation — o Navigation Component suporta deep links explícitos (PendingIntent + NavDeepLinkBuilder) e implícitos (através de intent-filter no manifesto). Um deep link pode levar a qualquer nó do nav_graph. Tratamento de notificações push: a Notification cria um PendingIntent com NavDeepLinkBuilder, que restaura a pilha de retorno e abre a tela desejada. O Navigation Component lida automaticamente com os botões Up/Back e retorna o usuário à tela anterior.

URL Routing: roteamento com Deeplink e Universal Link

URL Routing — roteamento baseado em esquemas de URL, deep links e universal links. A aplicação registra um esquema (myapp://profile/42) ou universal link (https://example.com/profile/42). O Router analisa a URL, extrai parâmetros (userId=42) e abre a tela correspondente. O URL Routing permite abrir a aplicação externamente: através de um link de site, email, notificação push, código QR. O iOS usa NSUserActivity + universal link, o Android — intent-filter + deep link.

swift
// URL Router — análise de deep link e navegação
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 — mapeamento de URLs com rotas
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
            }
        }
    }
}

Roteamento deep link na prática — a aplicação deve lidar com deep links em três estados: não iniciada (inicialização com deep link), em segundo plano (restauração do background), ativa (onNewIntent/SceneDelegate). O URL Router deve restaurar corretamente a pilha de retorno: ao fazer deep link para uma tela de perfil, o usuário deve poder pressionar Voltar e retornar à tela anterior. O iOS e o Android lidam com pilhas de retorno de forma diferente — o Router deve considerar as particularidades da plataforma.

Comparação do Router com Coordinator e Navigator

Router vs Coordinator — o Router responde à pergunta "como mostrar uma tela?" (push/present), o Coordinator — "qual tela mostrar?" (qual fluxo iniciar). O Router é uma ferramenta de navegação, o Coordinator é um organizador de fluxos. O Coordinator usa o Router. No VIPER, o Router desempenha ambas as funções: decide para onde ir e como mostrar. No MVVM-C, o Router é um protocolo separado usado pelo Coordinator. Os padrões não se excluem, mas se complementam.

CaracterísticaRouterCoordinatorNavigator
FocoMecânica de navegaçãoFluxo de navegaçãoAcesso global
NívelFramework UI (push/present)Lógica de negócio (fluxo)Infraestrutura
Criação de telasRecebe VC prontoCria VC via fábricaCria VC
Ciclo de vidaUm por navegaçãochildCoordinatorsSingleton

Router vs Navigator — Navigator é um nome mais antigo para Router na comunidade iOS. Em implementações iniciais, o Navigator era uma classe Singleton com métodos de navegação. Navigator é um Router singleton global. Navigator é mais simples, mas cria dependências ocultas. O Router baseado em protocolos é mais testável e modular. Navigator é adequado para projetos sem arquitetura estrita, Router — para Clean Architecture e VIPER.

Perguntas frequentes

Qual é a diferença entre Router e Coordinator?

Router é uma abstração sobre UINavigationController (push/present/pop). Coordinator é uma camada acima do Router que gerencia o fluxo (qual tela mostrar a seguir). O Router lida com a mecânica, o Coordinator com a lógica de navegação. O Coordinator usa o Router para realizar as transições. No VIPER, o Router combina ambas as funções; no MVVM-C, elas são separadas.

É obrigatório usar Router em uma aplicação mobile?

Não. Para aplicações com 3-5 telas, chamadas diretas a navigationController.pushViewController são uma solução perfeitamente válida. O Router torna-se útil com 10+ telas, deep links, notificações push e arquitetura modular. O Router simplifica os testes de navegação e permite o tratamento centralizado de transições de qualquer fonte (botão, deep link, notificação push).

Como o Router se relaciona com Deep Links?

URL Router é uma extensão do Router que analisa deep links e universal links. O URL Router determina o mapeamento entre URLs e telas da aplicação. Por exemplo, rota myapp://profile/42 → ProfileViewController(userId: 42). O URL Router centraliza o tratamento de deep links de diferentes fontes: notificações push, códigos QR, links de email, links universais.

Pode-se usar Router sem Coordinator?

Sim. O Router pode funcionar independentemente — como um Navigator global ou como um componente de módulo VIPER. Router sem Coordinator é simplesmente encapsular UINavigationController atrás de um protocolo. Coordinator sem Router é mais complexo (ViewController chama push/present diretamente), mas é possível. A melhor prática é Router + Coordinator juntos.

O Router no Android é o mesmo que o iOS Router?

Funcionalmente — sim, ambos centralizam a navegação. A implementação é diferente: iOS Router — protocolo + classe em torno de UINavigationController; Android — Jetpack Navigation Component com grafo XML e NavController. O Android Router está integrado ao framework (Navigation Component), o iOS Router é uma implementação de terceiros. O Android Router suporta Safe Args, o iOS Router não (precisa de generics ou Codable).

Resumo

  • Router — padrão de roteamento que encapsula a lógica de transição entre telas
  • iOS Router — protocolo com métodos push/present/pop em torno de UINavigationController
  • Android Router — Jetpack Navigation Component com XML nav_graph e NavController
  • URL Routing — roteamento via deep links e universal links
  • Router vs Coordinator — Router lida com a mecânica, Coordinator lida com o fluxo de navegação
  • Aplicação — arquitetura modular, deep links, testes de navegação

Vamos desenvolver um aplicativo móvel chave na mão

A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.

Discutir o projeto

Leia também