Router — iOSとAndroidにおけるルーティングパターンの基礎

著者: IT Sectr 公開日: 2026-02-19 読了時間: 9 分

Router(ルーター)— アプリケーションの画面間のナビゲーションロジックを集中化するアーキテクチャパターン。Routerは、イベント発生時にどこへどのように遷移するかを決定します。iOSではRouterはUINavigationControllerとsegueを抽象化し、AndroidではFragmentManagerとJetpack NavigationのNavControllerを抽象化します。Routerは独立したパターンとして、またはCoordinator(Router-per-Coordinator)やVIPER(Router-per-module)のコンポーネントとして機能できます。詳細はAndroid Navigation Component Guideをご覧ください。

重要ポイント

  • Router — 画面間のナビゲーションを集中化するルーティングパターン
  • 2つのレベル — RouterはCoordinatorのコンポーネントにも独立したパターンにもなれる
  • iOS Router — push/present/popメソッドを持つUINavigationControllerの抽象化
  • Android Router — NavControllerとdeep linksを備えたJetpack Navigation Component
  • URL Routing — URLスキーム(deeplink、universal link)に基づくルーティング

Routerとは:ルーティングパターンの本質

Router — 画面間の遷移ロジックをカプセル化するパターン。基本的な考え方:ViewController(またはPresenter/ViewModel)は直接navigationController.pushViewControllerを呼び出さず、遷移の意図をRouterに通知します。RouterはどのViewControllerを作成し、どのように表示するかを決定します。Routerは単純(ナビゲーションメソッドのセット)にも複雑(URLスキームルーティング、deep links、プッシュ通知付き)にもなります。

Routerの3つのアプローチ — サービスとしてのRouter(グローバルNavigatorシングルトン)、モジュールコンポーネントとしてのRouter(VIPERアプローチ)、プロトコルとしてのRouter(Coordinatorの抽象化)。グローバルRouter — シンプルさ(アプリ全体で1インスタンス)— 小規模プロジェクトで人気。モジュラーRouter — 各機能に独自のRouter — VIPERとClean Architectureの標準。プロトコルRouter — Coordinatorで使用:push/present/pop/dismissメソッドを持つRouterProtocol。

アプローチ構造使用するタイミング
グローバルNavigatorナビゲーションメソッドを持つシングルトン小規模プロジェクト、プロトタイプ
モジュラーRouter各モジュール内のRouterVIPER、Clean Architecture
プロトコルRouterCoordinator用のプロトコル+実装MVVM-C、Coordinatorパターン

パターンの歴史 — RouterはWebフレームワーク(URL Router — Rails Routes、Express.js)で登場し、モバイル開発に適応されました。iOSではVIPER(2015-2017)の台頭とともにRouterが普及しました。AndroidではRouterはJetpack Navigation(2018)の一部であり、Googleの標準ナビゲーションソリューションです。現在、Routerはモジュラーモバイルアプリケーションアーキテクチャの不可欠な部分です。

iOSのRouter:Swiftでの実装

iOS Router — さまざまなナビゲーションタイプのメソッドを持つプロトコル。基本的な実装はUINavigationControllerをラップします。Routerはモーダル表示(present/dismiss)、ナビゲーションスタックでのpush/pop、Split View ControllerのshowDetail、フルスクリーン表示(iOS 13+)を処理できます。RouterはViewControllerを作成せず、準備済みのインスタンスを受け取って表示します。ViewControllerの作成はファクトリ(Assembly、DIコンテナ)またはCoordinatorが行います。

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

// UINavigationControllerを使用したRouter実装
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
}

VIPERのRouter — 各VIPERモジュールには独自のRouterがあり、現在のモジュールからどの画面を開くかを認識しています。Routerはファクトリを通じて次のモジュールのViewControllerを作成し、制御を渡します。VIPERのRouterは、import UIKitを含む唯一のコンポーネントです(Viewを除く)。これによりPresenterとInteractorのテストが簡素化されます:UIKitに依存しません。

AndroidのRouter:Jetpack Navigation Component

Jetpack Navigation Component — Androidの標準ルーターで、2018年からGoogleが推奨しています。ナビゲーションはXMLグラフ(nav_graph.xml)で定義されます:ノード(fragments、activities、destinations)とエッジ(actions)。NavControllerが遷移を管理します:FragmentManager.replace/addを呼び出し、バックスタックを管理します。Navigation Componentはdeep links、引数、遷移アニメーション、type-safeなデータ受け渡しのための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)
    }
}

Android NavigationのDeep links — Navigation Componentは明示的なdeep links(PendingIntent + NavDeepLinkBuilder)と暗黙的なdeep links(マニフェストのintent-filter経由)をサポートしています。deep linkはnav_graphの任意のノードに遷移できます。プッシュ通知の処理:NotificationがNavDeepLinkBuilderでPendingIntentを作成し、バックスタックを復元して目的の画面を開きます。Navigation ComponentはUp/Backボタンを自動的に処理し、ユーザーを前の画面に戻します。

URL Routing:DeeplinkとUniversal Linkルーティング

URL Routing — URLスキーム、deep links、universal linksに基づくルーティング。アプリはスキーム(myapp://profile/42)またはuniversal link(https://example.com/profile/42)を登録します。RouterはURLを解析し、パラメータ(userId=42)を抽出して、対応する画面を開きます。URL Routingにより、アプリを外部から開くことができます:Webサイトリンク、メール、プッシュ通知、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ルーティング — アプリは3つの状態でdeep linksを処理する必要があります:未起動(deep linkでの起動)、バックグラウンド(バックグラウンドからの復元)、アクティブ(onNewIntent/SceneDelegate)。URL Routerはバックスタックを正しく復元する必要があります:プロフィール画面にdeep linkする場合、ユーザーが戻るボタンを押して前の画面に戻れるようにする必要があります。iOSとAndroidではバックスタックの処理が異なるため、Routerはプラットフォーム固有の特性を考慮する必要があります。

RouterとCoordinator、Navigatorの比較

Router vs Coordinator — Routerは「画面をどのように表示するか?」(push/present)に答えます。Coordinatorは「どの画面を表示するか?」(どのフローを開始するか)に答えます。Routerはナビゲーションツールであり、Coordinatorはフローオーガナイザーです。CoordinatorはRouterを使用します。VIPERではRouterが両方の機能を果たします:どこへ行くかとどのように表示するかを決定します。MVVM-CではRouterはCoordinatorが使用する別のプロトコルです。これらのパターンは相互に排他的ではなく、補完し合います。

特性RouterCoordinatorNavigator
焦点ナビゲーションの仕組みナビゲーションフローグローバルアクセス
レベルUIフレームワーク(push/present)ビジネスロジック(フロー)インフラストラクチャ
画面作成準備済みVCを受け取るファクトリ経由でVCを作成VCを作成
ライフサイクルナビゲーションごとに1つchildCoordinatorsシングルトン

Router vs Navigator — NavigatorはiOSコミュニティにおけるRouterの古い名称です。初期の実装では、Navigatorはナビゲーションメソッドを持つシングルトンクラスでした。NavigatorはグローバルRouterシングルトンです。Navigatorはよりシンプルですが、隠れた依存関係を生み出します。プロトコルベースのRouterはよりテスト可能でモジュール化されています。Navigatorは厳格なアーキテクチャがないプロジェクトに適しており、RouterはClean ArchitectureとVIPERに適しています。

よくある質問

RouterとCoordinatorの違いは何ですか?

RouterはUINavigationController(push/present/pop)の抽象化です。CoordinatorはRouterの上層レイヤーで、フロー(次にどの画面を表示するか)を管理します。Routerは仕組みを担当し、Coordinatorはナビゲーションロジックを担当します。Coordinatorは遷移を実行するためにRouterを使用します。VIPERではRouterが両方の機能を兼ね備えていますが、MVVM-Cでは分離されています。

モバイルアプリでRouterの使用は必須ですか?

いいえ。3〜5画面のアプリでは、navigationController.pushViewControllerの直接呼び出しで十分です。Routerは10画面以上、deep links、プッシュ通知、モジュラーアーキテクチャの場合に有用になります。Routerはナビゲーションのテストを簡素化し、任意のソース(ボタン、deep link、プッシュ通知)からの遷移を集中管理できます。

RouterとDeep Linksの関係は?

URL RouterはRouterの拡張で、deep linksとuniversal linksを解析します。URL RouterはURLとアプリ画面の間のマッピングを決定します。例:ルートmyapp://profile/42 → ProfileViewController(userId: 42)。URL Routerはプッシュ通知、QRコード、メールリンク、ユニバーサルリンクなど異なるソースからのdeep link処理を集中化します。

RouterはCoordinatorなしで使用できますか?

はい。Routerは独立して機能できます — グローバルNavigatorとしてもVIPERモジュールコンポーネントとしても。CoordinatorなしのRouterは、単にUINavigationControllerをプロトコルの背後にカプセル化するだけです。CoordinatorなしのRouterはより複雑ですが(ViewControllerが直接push/presentを呼び出す)、可能です。ベストプラクティスはRouter + Coordinatorを一緒に使用することです。

AndroidのRouterはiOSのRouterと同じですか?

機能的には — はい、両方ともナビゲーションを集中化します。実装は異なります:iOS Router — UINavigationControllerをラップするプロトコル+クラス;Android — XMLグラフとNavControllerを備えたJetpack Navigation Component。Android Routerはフレームワーク(Navigation Component)に組み込まれており、iOS Routerはサードパーティの実装です。Android RouterはSafe Argsをサポートしていますが、iOS Routerはサポートしていません(genericsまたはCodableが必要)。

まとめ

  • Router — 画面間の遷移ロジックをカプセル化するルーティングパターン
  • iOS Router — UINavigationControllerをラップするpush/present/popメソッドのプロトコル
  • Android Router — XML nav_graphとNavControllerを備えたJetpack Navigation Component
  • URL Routing — deep linksとuniversal linksによるルーティング
  • Router vs Coordinator — Routerは仕組みを、Coordinatorはナビゲーションフローを担当
  • 適用 — モジュラーアーキテクチャ、deep links、ナビゲーションテスト

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談

こちらもお読みください