PAYATHON 2026

APP内嵌Webview打开H5支付页时Android无法唤起支付宝

支付老李

结论

Android 的 WebView 通常不会自动处理支付宝的 alipays://、intent:// 等跳转协议,而系统浏览器和部分 iOS WebView 可能会处理。支付页尝试唤起支付宝时,如果 APP 没有在 WebViewClient 中拦截这些链接并交给系统处理,唤起就会失败,页面随后会降级为“复制口令支付”。

这类问题通常与支付宝账号或支付订单无关,原因在于 Android WebView 处理外部应用协议的方式不同。

产生差异的原因

支付宝 H5 支付页唤起客户端时,可能使用以下链接:

alipays://platformapi/startapp?...

或者:

intent://platformapi/startapp?...#Intent;scheme=alipays;package=com.eg.android.AlipayGphone;end

普通的 https:// 链接可以继续在 WebView 中加载,自定义协议则需要交给 Android 系统的 Intent 处理。WebView 默认不会替宿主 APP 执行这一步。

iOS 使用另一套 URL Scheme 或 Universal Link 调度机制,实际表现还会受 WebView 类型、支付宝版本和支付产品配置影响。iOS 能唤起支付宝,并不意味着 Android 也会自动唤起。

“复制口令”一般是支付页发现无法直接打开支付宝客户端后启用的兼容方案。

Android 处理方式

可以在 WebViewClient 中拦截非 HTTP 链接,并通过系统 Intent 处理支付宝协议。下面是一个 Kotlin 示例:

private const val ALIPAY_PACKAGE = "com.eg.android.AlipayGphone"

webView.webViewClient = object : WebViewClient() {

    override fun shouldOverrideUrlLoading(
        view: WebView,
        request: WebResourceRequest
    ): Boolean {
        return handleUrl(view.context, request.url.toString())
    }

    @Suppress("DEPRECATION")
    override fun shouldOverrideUrlLoading(
        view: WebView,
        url: String
    ): Boolean {
        return handleUrl(view.context, url)
    }
}

private fun handleUrl(context: Context, url: String): Boolean {
    return when {
        url.startsWith("http://") || url.startsWith("https://") -> {
            false
        }

        url.startsWith("alipays://") || url.startsWith("alipay://") -> {
            try {
                val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url)).apply {
                    addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                    setPackage(ALIPAY_PACKAGE)
                }
                context.startActivity(intent)
            } catch (e: ActivityNotFoundException) {
                // 未安装支付宝,保留支付页自身的口令或下载引导
            }
            true
        }

        url.startsWith("intent://") -> {
            try {
                val intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME).apply {
                    addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                    setPackage(ALIPAY_PACKAGE)
                }
                context.startActivity(intent)
            } catch (e: Exception) {
                // intent 格式无效、未安装支付宝或系统无法处理
            }
            true
        }

        else -> {
            // 不要直接打开任意自定义协议
            false
        }
    }
}

同时需要确认 WebView 的基础能力已经启用:

webView.settings.javaScriptEnabled = true
webView.settings.domStorageEnabled = true

是否必须启用 JavaScript 和 DOM Storage,取决于具体的支付页面,不过多数 H5 收银台会依赖这些能力。

Android 11 及以上的应用可见性

如果业务代码需要通过 PackageManager 检查支付宝是否已安装,Android 11 及以上还要在 AndroidManifest.xml 中声明查询范围:

<manifest>
    <queries>
        <package android:name="com.eg.android.AlipayGphone" />
    </queries>

    <application>
        <!-- ... -->
    </application>
</manifest>

这项配置主要影响“是否安装”的查询结果。添加配置后,WebView 仍不会自动唤起支付宝,APP 依然需要拦截协议并调用 startActivity()。

建议的排查步骤

  1. 在 shouldOverrideUrlLoading() 中记录支付过程产生的 URL,确认其中是否有 alipays:// 或 intent://。
  2. 如果完全没有出现唤起协议,检查支付接口返回内容、支付产品类型、User-Agent 和支付宝商户侧配置。
  3. 如果出现了协议却没有跳转,检查回调是否返回 true,以及代码是否实际调用了 startActivity()。
  4. 捕获 ActivityNotFoundException,确认设备是否安装支付宝,以及支付宝是否被系统停用。
  5. 分别使用系统浏览器和 APP WebView 测试。同一订单能在浏览器中唤起支付宝,却无法在 WebView 中唤起,通常说明问题出在宿主 APP 的协议处理上。
  6. 如果是原生 APP 支付场景,优先评估支付宝 APP 支付 SDK,不要只为复用网页流程而强行使用 H5 支付。

注意事项

不要把所有非 http、https 链接直接传给 Intent。支付页面属于外部内容,如果不加限制地打开任意 Scheme,可能带来安全风险。应限制允许使用的协议和目标包名,并校验 intent:// 中的组件、包名和回退地址。

也不建议伪造浏览器 User-Agent,强制支付页使用某种唤起流程。这样做可能绕过页面的环境判断,却无法解决 WebView 不处理自定义协议的问题,还可能引发回跳、风控或兼容性异常。

如果接入的是支付宝特定 H5 支付产品,还要遵守该产品当前的接入条件。部分能力可能对 WebView、域名、回跳地址或客户端环境另有要求,修改 Android 代码不能替代正确的商户侧配置。

备注:内容仅供参考。