🏃‍♂️

Android | Compose でディープリンクを実装するときはクエリパラメータにデフォルト値を設定しよう

2023/05/14に公開

はじめに

Compose を使ったアプリを開発していて以下のエラーでハマったので備忘録です。

java.lang.IllegalArgumentException: Navigation destination that matches request NavDeepLinkRequest{ uri=android-app://androidx.navigation/login } cannot be found in the navigation graph NavGraph(0x0) startDestination={Destination(0xa268bffc) route=login}

何が起こったのか

ナビゲーションを使って login ルート(ログイン画面)に遷移させようとしたとき、上記のエラーが発生してしまいました。login へのルートは以下のように定義していました。

NavHost(startDestination = "login") {
    loginNavGraph()
    homeNavGraph()
    ...
}

@OptIn(ExperimentalAnimationApi::class)
fun NavGraphBuilder.loginNavGraph() {
    composable(
        route = "login",
        deepLinks = listOf(navDeepLink { uriPattern = "myapp://login?code={code}" }),
        arguments = listOf(navArgument("code") { type = NavType.StringType })
    ) { backStackEntry ->
        ...
    }
}

@OptIn(ExperimentalAnimationApi::class)
fun NavGraphBuilder.homeNavGraph() {
    ...
}

ログイン画面には NavHostController.navigate("login") 以外にも myapp://login でディープリンクできるようになっています。エラーになったのは前者の navigate() による遷移のときです。

解決方法

ディープリンクの URI で設定したクエリパラメータ(今回では code )にデフォルト引数を設定することで解消できました。

@OptIn(ExperimentalAnimationApi::class)
fun NavGraphBuilder.loginNavGraph(navigateToHome: () -> Unit) {
    composable(
        route = "login",
        deepLinks = listOf(navDeepLink { uriPattern = "myapp://login?code={code}" }),
        arguments = listOf(
            navArgument("code") {
                type = NavType.StringType
                defaultValue = "" // デフォルト値を設定
            }
        )
    ) { backStackEntry ->
        ...
    }
}

原因はハッキリとわかっていないのですが、composable() でルートを定義するとき arguments に何かを設定(例えば code)を設定すると、route = "login" の場合でも route = "login?code={code}" のように振る舞うようになっているのかなと推測しました。デフォルト値を設定すれば navigate("login?code={デフォルト値}") と同じ動きをしてくれるのかな。。

Discussion