如何在 Android Jetpack Compose Webview 中处理重定向 URL

问题描述 投票:0回答:1

我正在使用 Kotlin 和 Jetpack Compose 创建一个 Android 应用程序,我有一个显示 Web 视图的可组合屏幕。

屏幕说明

  • Webview 加载 Mollie 付款 URL,其中显示付款选项 不同的银行 每个选项都有一个重定向到银行的深层链接 应用程序(如果安装了该应用程序) 银行应用程序的付款流程返回 重定向网址

需要什么?

  • 来自深层链接的重定向 URL 应在我的应用程序的 Web 视图中打开 而不是在网络浏览器中打开(在本例中为 Google Chrome)

这是Redirect Url的模式

https://www.mollie.com/checkout/ideal/return/SOMETOKEN?trxid=SOMEVALUE=SOMEVALUE

下面是AndroidManifest.xml的代码

<activity
        android:name=".presentation.feature.dashboard.MainActivity"
        android:exported="true"
        android:launchMode="singleTask"
        android:windowSoftInputMode="adjustResize">
        <intent-filter>
             <action android:name="android.intent.action.MAIN" />

             <category android:name="android.intent.category.LAUNCHER" />
         </intent-filter>
        
        <intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
            <category android:name="android.intent.category.BROWSABLE" />
            <data
                android:host="ideal"
                android:scheme="intent" />
            <data
                android:host="x-bunq-app"
                android:scheme="bunq" />
            <data
                android:host="payment"
                android:scheme="nl-asnbank-ideal" />
            <data
                android:host="ideal.ing.nl"
                android:scheme="intent" />
            <data
                android:host="authenticate"
                android:scheme="intent" />
            <data
                android:host="ideal2.knab.nl"
                android:scheme="knabapp" />
            <data
                android:host="payment"
                android:scheme="nl-regiobank-ideal" />
            <data
                android:host="payment"
                android:scheme="nl-snsbank-ideal" />

        </intent-filter>


    </activity>

可组合屏幕代码

val USER_AGENT_MOZILLA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:101.0) AppleWebKit/605.1.15 (KHTML, like Gecko) Chrome/114.0.0.0 Mobile Safari/605.1.15"
@RequiresApi(Build.VERSION_CODES.O)
@SuppressLint("SetJavaScriptEnabled")
@Composable
fun BookingPaymentScreen(
    navController: NavController,
    addBookingViewModel: AddBookingViewModel,
) {
    val context = LocalContext.current
    val scope = rememberCoroutineScope()
    val result = navController.previousBackStackEntry?.savedStateHandle?.get<Boolean>("isFromRetry")
    val resultUrl = navController.previousBackStackEntry?.savedStateHandle?.get<String>("url")
    val errorToastState = remember { mutableStateOf(false) }
    val launcher = rememberLauncherForActivityResult(
        contract = ActivityResultContracts.StartActivityForResult(),
        onResult = {
            activityResult ->
        }
    )
    BackHandler {
        goBackBookingPaymentScreen(addBookingViewModel, navController)
    }
    //First time
    if (result == true) {
        if (!addBookingViewModel.retryCallMade) {
            addBookingViewModel.onEvent(AddBookingUiEvent.onRetryPayment)
            addBookingViewModel.retryCallMade = true
        }
    }
    Surface(
        modifier = Modifier
            .background(
                color = PallaAppTheme.colors.primary
            )
            .fillMaxHeight()
            .statusBarsPadding()
    ) {
        if (errorToastState.value) {
            Toast.makeText(context, "App not installed", Toast.LENGTH_LONG)
                .show()
            errorToastState.value = false
        }
        if (addBookingViewModel.checkoutLoading) {
            Box(
                modifier = Modifier
                    .fillMaxSize()
                    .padding(AppVariables.AppPading)
                    .background(PallaAppTheme.AppBackground),
                contentAlignment = Alignment.Center
            ) {
                CircularProgressIndicator(
                    modifier = Modifier.size(20.dp),
                    color = PallaAppTheme.colors.secondary,
                    strokeWidth = 2.dp
                )
            }
        } else {
            AndroidView(
                modifier = Modifier
                    .fillMaxSize()
                    .statusBarsPadding()
                    .navigationBarsPadding(),
                factory = { context ->
                    WebView(context).apply {
                        settings.javaScriptEnabled = true
                        settings.userAgentString = USER_AGENT_MOZILLA
                        settings.domStorageEnabled = true
                        settings.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
                        settings.allowContentAccess = true
                        settings.loadWithOverviewMode = true
                        webViewClient = object : WebViewClient() {
                            override fun onPageCommitVisible(view: WebView?, url: String?) {
                                super.onPageCommitVisible(view, url)
                            }

                            override fun onPageStarted(
                                view: WebView?,
                                url: String?,
                                favicon: Bitmap?
                            ) {
                                super.onPageStarted(view, url, favicon)
                            }

                            override fun onPageFinished(view: WebView?, url: String?) {
                                super.onPageFinished(view, url)
                            }

                            @Deprecated("Deprecated in Java")
                            override fun shouldOverrideUrlLoading(
                                view: WebView?,
                                url: String?
                            ): Boolean {
                                if (url != null && url.startsWith(AppDeepLinks.COURT_BOOKING)) {
                                    addBookingViewModel.retryCallMade = false
                                    val bookingDetail = BookingDetail(
                                        bookingId = addBookingViewModel.bookingFinalUiState.bookingId,
                                        ownerToken = addBookingViewModel.bookingFinalUiState.ownerToken,
                                        url = addBookingViewModel.bookingFinalUiState.paymentUrl
                                    )
                                    navController.currentBackStackEntry?.savedStateHandle?.set(
                                        key = "bookingDetail",
                                        value = bookingDetail
                                    )
                                    navController.navigate(BOOKING_DETAIL_ROUTE)
                                    return true
                                }
                                if (isDeepLink(url)
                                ) {
                                    try {
                                        val intent = Intent(ACTION_VIEW, Uri.parse(url))
                                        context.startActivity(intent)

                                    } catch (e: ActivityNotFoundException) {
                                        // Only browser apps are available, or a browser is the default.
                                        // So you can open the URL directly in your app, for example in a
                                        errorToastState.value = true
                                    }
                                    return true
                                }
                                // return super.shouldOverrideUrlLoading(view, url)
                                return false
                            }
                        }
                        var url = addBookingViewModel.bookingFinalUiState.paymentUrl
                        if (url.isEmpty()) {
                            url = resultUrl ?: ""
                        }
                        loadUrl(url)
                    }
                },
                update = { webView ->
                    // Update the WebView if needed
                    CookieManager.getInstance()?.setAcceptThirdPartyCookies(webView, true)
                }
            )
        }

    }
}

fun goBackBookingPaymentScreen(
    addBookingViewModel: AddBookingViewModel,
    navController: NavController
) {
    addBookingViewModel.retryCallMade = false
    val bookingDetail = BookingDetail(
        bookingId = addBookingViewModel.bookingFinalUiState.bookingId,
        ownerToken = addBookingViewModel.bookingFinalUiState.ownerToken
    )
    navController.currentBackStackEntry?.savedStateHandle?.set(
        key = "bookingDetail",
        value = bookingDetail
    )
    navController.navigate(BOOKING_DETAIL_ROUTE)
}

fun isDeepLink(url: String?): Boolean {
    if ((url?.startsWith("nl") == true && url.contains("payloadUri"))
    ) {
        return true
    }
    if (url?.startsWith("http") == false && !url.startsWith("https") && url.contains("://")) {
        return true
    }
    return false
}

我在这里缺少的任何帮助,即不允许我的应用程序接收重定向网址,而是在用户的网络浏览器中打开重定向网址。

android android-studio android-jetpack-compose android-webview mollie
1个回答
0
投票

您还没有在您的应用程序和网站中正确设置深层链接。

如果您不希望链接在外部网络浏览器中打开,您需要将 https://yourdomain/.well-known/assetlinks.json 与以下内容放在一起。

[{
  "relation": ["delegate_permission/common.handle_all_urls"],
  "target": {
    "namespace": "android_app",
    "package_name": "your_com.example",
    "sha256_cert_fingerprints":
    ["YOUR_CERTIFICATE"]
  }
}]

注意:您可以从此 URL 创建上述文件: https://developers.google.com/digital-asset-links/tools/generator

您可以使用以下命令生成应用程序的 SHA256 指纹:

keytool -list -v -keystore <keystore path> -alias <key alias> -storepass <store password> -keypass <key password>
© www.soinside.com 2019 - 2024. All rights reserved.