Android составляет навигацию - как я могу передать аргумент типа URL?

Я разрабатываю образец аутентификации Firebase Email Link с использованием Jetpack Compose & Navigation.

Если пользователь вводит адрес электронной почты и пытается выполнить аутентификацию, на адрес электронной почты отправляется сообщение. Когда пользователь открывает и щелкает ссылку электронной почты, приложение снова открывается.

Он использует динамическую ссылку Firebase.

Итак, когда приложение снова открывается, я могу получить emailLink из динамической ссылки. И я передаю его на целевую страницу (Главная).

Firebase.dynamicLinks
    .getDynamicLink(intent)
    .addOnSuccessListener(this@MainActivity) { pendingDynamicLinkData: PendingDynamicLinkData? ->
        if (pendingDynamicLinkData != null) {
            val emailLink = intent?.data?.toString()
            if (emailLink != null && firebaseAuth.isSignInWithEmailLink(emailLink)) {
                intent = null
                navController.navigate("${Home.route}?emailLink = {$emailLink}")
            }
        }
    }
}

Мой код NavHost:

NavHost(
    navController = navController,
    startDestination = Home.route,
) {
    composable(
        route = "${Home.route}?emailLink = {emailLink}",
        arguments = listOf(navArgument("emailLink") {
            type = NavType.StringType
            nullable = true
            defaultValue = null
        })
    ) { backStackEntry ->
        val emailLink = backStackEntry.arguments?.getString("emailLink")
        Log.i("TEST", "[sample] navigate - emailLink: $emailLink")
        HomeScreen(
            vm = hiltViewModel(),
            emailLink = emailLink
        )
    }
}

Проблема в... Оригинал emailLink это:

https://email-link-auth-sample-95a4a.firebaseapp.com/__/auth/action?apiKey=AIzaSyD2w6bRHiqEXaSx9W0N5Mq5obydIjRk_mw&mode=signIn&oobCode=dj8M6b4Rq6dwM81ziExyw_3-gXiExQY8FvHNAZsPDxMAAAGETZgg0w&continueUrl=https://emaillinkauthsample.page.link&lang=en

Но когда я получаю это от backStackEntry.arguments?.getString("emailLink"), emailLink это:

{https://email-link-auth-sample-95a4a.firebaseapp.com/__/auth/action?apiKey=AIzaSyD2w6bRHiqEXaSx9W0N5Mq5obydIjRk_mw

Я думаю, что система составления навигации была разработана на основе системы URL. Так что в этом случае он работает некорректно.

Есть ли хорошее решение...?

На самом деле, я написал код с помощью savedStateHandle, и он отлично работает.

Firebase.dynamicLinks
    .getDynamicLink(intent)
    .addOnSuccessListener(this@MainActivity) { pendingDynamicLinkData: PendingDynamicLinkData? ->
        if (pendingDynamicLinkData != null) {
            val emailLink = intent?.data?.toString()
            if (emailLink != null && firebaseAuth.isSignInWithEmailLink(emailLink)) {
                intent = null

                // navController.navigate("${Home.route}?emailLink = {$emailLink}")

                /**
                 * my workaround code using the `savedStateHandle`
                 */
                navController.currentBackStackEntry?.savedStateHandle?.apply {
                  set("emailLink", emailLink)
                }
                navController.navigate(Home.route)
            }
        }
    }
}

NavHost(
    navController = navController,
    startDestination = Home.route,
) {
    composable(
        route = "${Home.route}?emailLink = {emailLink}",
        arguments = listOf(navArgument("emailLink") {
            type = NavType.StringType
            nullable = true
            defaultValue = null
        })
    ) { backStackEntry ->
        // val emailLink = backStackEntry.arguments?.getString("emailLink")

        /**
         * my workaround code using the `savedStateHandle`
         */
        val emailLink = navController.previousBackStackEntry?.savedStateHandle?.get<String>("emailLink")
        HomeScreen(
            vm = hiltViewModel(),
            emailLink = emailLink
        )
    }
}

Вы можете найти код здесь: https://github.com/yoonhok524/Email-Link-Auth-Sample


1
89
1

Ответ:

Решено

Я решил эту проблему. Если я закодирую URL-ссылку, а затем передам ее, она будет работать нормально!

Firebase.dynamicLinks
    .getDynamicLink(intent)
    .addOnSuccessListener(this@MainActivity) { pendingDynamicLinkData: PendingDynamicLinkData? ->
        if (pendingDynamicLinkData != null) {
            val emailLink = intent?.data?.toString()
            if (emailLink != null && firebaseAuth.isSignInWithEmailLink(emailLink)) {
                intent = null

                // navController.navigate("${Home.route}?emailLink = {$emailLink}")


                /**
                 * my workaround code using the `savedStateHandle`
                 */
                // navController.currentBackStackEntry?.savedStateHandle?.apply {
                //   set("emailLink", emailLink)
                // }
                // navController.navigate(Home.route)


                /**
                 * my solution code
                 */
                val encodedEmailLink = withContext(Dispatchers.IO) {
                  URLEncoder.encode(it, StandardCharsets.UTF_8.toString())
                }
                navController.navigate(Home.getRoute(encodedEmailLink))
            }
        }
    }
}