Navigation 3 に移行する

Navigation 3 は、Jetpack Compose でナビゲーションの状態を処理する方法の根本的な変化を表しており、Navigation 2 よりもアーキテクチャ上の利点が大幅に向上しています。

Wear Compose アプリを Navigation 2 から Navigation 3 に移行するために必要なアーキテクチャの変更と手順について説明します。

Navigation 3 の主な利点

  • 直接的なバックスタック制御: NavBackStack は、ユーザーがアクセスした画面の履歴を表す NavKey オブジェクトの可変リストにすぎません。Kotlin のMutableList と同様に制御できます(addremoveLastclear)。リストを直接操作して、キーを追加して進む、キーを削除して戻るなどのナビゲーション アクションを実行します。
  • Compose ファースト設計: バックスタックは標準のオブザーバブルな 状態としてモデル化されます。ナビゲーション履歴を変更すると、他の Compose の状態を更新する場合とまったく同じように動作し、自動的に再コンポーズがトリガーされて現在の画面が表示されます。
  • デフォルトで型安全: 文字列ベースのルートは完全に排除されます。 ナビゲーションでは、シリアル化可能なデータ オブジェクトとデータクラスが使用されます。
  • プレゼンテーションの分離(シーン戦略): UI 遷移レイヤ (NavDisplaySwipeDismissableSceneStrategy)は状態トラッキング(NavBackStack)から完全に 分離されているため、組み込みの Wear OS ナビゲーション遷移を簡単に 統合できます。

移行手順

1. 依存関係を更新する

古い androidx.wear.compose:compose-navigation 依存関係を削除し、Kotlin シリアル化のサポートとともに、分割された新しい Navigation 3 の依存関係を導入します。

以下を削除します。

implementation("androidx.wear.compose:compose-navigation:...")

以下を追加します。

implementation("androidx.navigation3:navigation3-runtime:...") // State logic
implementation("androidx.navigation3:navigation3-ui:...")      // Display logic
implementation("androidx.wear.compose:compose-navigation3:...") // Wear gestures
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:...") // Requires compiler plugin

2. NavKey を実装するようにリンク先を更新する

Navigation 2 では、ルーティングに文字列または汎用オブジェクトを使用していた可能性があります。Navigation 3 では、実装し、すべての画面オブジェクトに @Serializable アノテーションを付ける必要がありますNavKey

なぜこれが必要なのですか?プロセスが終了してもバックスタックを保存して 復元できるようにするため、基盤となる navigation3-runtimekotlinx-serialization を使用して状態をシリアル化します。

前(Navigation 2 - 汎用的な型安全ルート):

sealed class Nav2Screen {
    data object Landing : Nav2Screen()
    data object List : Nav2Screen()
}

後(Navigation 3 - NavKey + シリアル化可能):

@Serializable
sealed interface MigrationScreen : NavKey {
    @Serializable
    data object Landing : MigrationScreen

    @Serializable
    data object List : MigrationScreen
}

3. ルーティング ロジックを置き換える(NavController から NavBackStack

NavControllerNavBackStack initialized via rememberNavBackStack に置き換えます。また、Wear OS 用に SwipeDismissableSceneStrategyをインスタンス化する必要があります。

前(Navigation 2):

val navController = rememberSwipeDismissableNavController()

後(Navigation 3):

val backStack = rememberNavBackStack(MigrationScreen.Landing as NavKey)
val strategy = rememberSwipeDismissableSceneStrategy<NavKey>()

4. NavHostNavDisplayentryProvider DSL に置き換える

NavHost コンテナとその内部の composable("route") { ... } ビルダー DSL は、NavDisplayentryProvider { entry<Key> { ... } } DSL に置き換えられます。

前(Navigation 2):

SwipeDismissableNavHost(navController = navController, startDestination = "menu") {
    composable("menu") {
        GreetingScreen(
            onShowList = { navController.navigate("list") }
        )
    }
    composable("list") {
        ListScreen()
    }
}

後(Navigation 3):

NavDisplay(
    backStack = backStack,
    sceneStrategies = listOf(strategy),
    entryProvider = entryProvider {
        entry<MigrationScreen.Landing> {
            GreetingScreen(
                onShowList = { backStack.add(MigrationScreen.List) }
            )
        }
        entry<MigrationScreen.List> {
            ListScreen()
        }
    }
)