PAYATHON 2026

Android webview 中 H5 支付无法跳转至支付宝

支付阿杰

结论

表单通常已经提交,问题多半出在支付宝收银台后续跳转到了 alipays://、intent:// 等 WebView 无法识别的协议。普通浏览器会唤起支付宝 App,而 Android WebView 需要宿主应用通过 WebViewClient 拦截并处理这些 URL。

也不建议直接替换整个 body.innerHTML。先确认后端返回了完整、有效的支付表单,再将表单插入独立容器并提交。

先确认问题发生在哪一步

通过 WebViewClient 记录跳转 URL,查看表单提交后的实际情况:

  • 如果出现 alipays:// 或 intent://,需要由 Android 端唤起支付宝。
  • 如果出现 net::ERR_UNKNOWN_URL_SCHEME,说明 WebView 无法处理该自定义协议。
  • 如果页面一直没有变化,应检查表单内容、JavaScript 配置和控制台错误。
  • 如果已经进入支付宝网页收银台,但无法继续,应检查 WebView 的 Cookie、网络请求和 HTTPS 配置。

后端返回的表单至少要有有效的 action、method 和支付参数,例如:

<form id="alipayForm"
      action="https://example-alipay-cashier-url"
      method="post">
    <input type="hidden" name="biz_content" value="...">
</form>

不要在客户端自行拼接或修改支付宝签名参数,否则可能导致验签失败。

改进 H5 的表单提交方式

原代码会替换整个页面的 body:

document.getElementsByTagName('body')[0].innerHTML =
    res.data.benefitsInfo.form;
document.forms[0].submit();

这样可能破坏当前页面的 DOM、事件绑定和运行环境。可以改为创建独立容器:

const formHtml = res.data.benefitsInfo.form;

const container = document.createElement('div');
container.style.display = 'none';
container.innerHTML = formHtml;
document.body.appendChild(container);

const form = container.querySelector('form');
if (!form) {
  throw new Error('支付接口未返回有效的 form');
}

form.submit();

如果返回内容包含 <script>,使用 innerHTML 插入后,脚本通常不会像正常加载页面时那样自动执行。不过,支付宝支付表单一般只需找到 form 并调用 submit(),不应依赖返回字符串中的脚本。

还可以检查:

console.log(form.action);
console.log(form.method);
console.log(new FormData(form));

生产日志中不要输出签名、订单信息或用户敏感数据。

Android 端处理支付宝协议

给 WebView 设置 WebViewClient,遇到支付宝协议时通过 Intent 打开:

webView.setWebViewClient(new WebViewClient() {
    @Override
    public boolean shouldOverrideUrlLoading(
            WebView view,
            WebResourceRequest request
    ) {
        return handleUrl(view, request.getUrl().toString());
    }

    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        return handleUrl(view, url);
    }

    private boolean handleUrl(WebView view, String url) {
        Uri uri = Uri.parse(url);
        String scheme = uri.getScheme();

        if ("http".equalsIgnoreCase(scheme)
                || "https".equalsIgnoreCase(scheme)) {
            return false;
        }

        if ("alipays".equalsIgnoreCase(scheme)) {
            try {
                Intent intent = new Intent(Intent.ACTION_VIEW, uri);
                view.getContext().startActivity(intent);
            } catch (ActivityNotFoundException e) {
                // 未安装支付宝,可提示用户或跳转到可信的网页支付地址
            }
            return true;
        }

        if ("intent".equalsIgnoreCase(scheme)) {
            try {
                Intent intent = Intent.parseUri(
                        url,
                        Intent.URI_INTENT_SCHEME
                );

                PackageManager pm = view.getContext().getPackageManager();
                if (intent.resolveActivity(pm) != null) {
                    view.getContext().startActivity(intent);
                    return true;
                }

                String fallbackUrl =
                        intent.getStringExtra("browser_fallback_url");

                if (fallbackUrl != null
                        && (fallbackUrl.startsWith("https://")
                        || fallbackUrl.startsWith("http://"))) {
                    view.loadUrl(fallbackUrl);
                }
            } catch (Exception e) {
                // 记录异常并给出支付失败提示
            }
            return true;
        }

        return true;
    }
});

同时确认 WebView 已启用业务需要的 JavaScript:

WebSettings settings = webView.getSettings();
settings.setJavaScriptEnabled(true);
settings.setDomStorageEnabled(true);

只在页面确实需要时启用 JavaScript,并确保 WebView 不会加载来源不可信的页面。

兼容未安装支付宝的情况

设备未安装支付宝时,startActivity() 可能抛出 ActivityNotFoundException。可以提示用户安装支付宝,也可以使用支付接口提供的网页收银台降级地址,或者将可信的 HTTPS 支付地址交给系统浏览器打开。

不要将 alipays:// 地址直接传给 webView.loadUrl(),WebView 本身无法处理这种协议。

还需要检查的配置

HTTPS 与混合内容

如果当前 H5 使用 HTTPS,但支付链路中包含 HTTP 资源,Android WebView 可能会拦截混合内容。应优先让整个支付链路都使用 HTTPS,不建议为了兼容而全局放开混合内容。

部分网页收银台依赖 Cookie。如果日志显示页面已经进入 HTTPS 收银台,但会话丢失,可以检查 Cookie 是否可用:

CookieManager cookieManager = CookieManager.getInstance();
cookieManager.setAcceptCookie(true);
cookieManager.setAcceptThirdPartyCookies(webView, true);

是否需要第三方 Cookie,要根据实际支付链路、网络请求和支付宝当前的接入文档判断。

WebView 版本

Chrome 62 对应的 WebView 内核已经较旧,可能有兼容性问题。可以更新设备上的 Android System WebView 或 Chrome 后重新测试,但不能只根据版本判断根因。应先查看表单提交后的 URL、WebView 控制台和网络错误。

安全注意事项

不要对所有非 HTTP URL 一律执行 Intent。WebView 页面可能构造恶意协议,因此需要限制处理范围:

  • 只允许明确的协议,例如 alipays 和业务确实需要的 intent。
  • 限制 WebView 可以加载的支付域名。
  • 校验 browser_fallback_url,只允许可信的 HTTP/HTTPS 地址。
  • 不要将后端返回的任意 HTML 插入页面,除非内容来自可信的支付接口。
  • 订单金额、商户号和回调结果必须由服务端校验,不能根据 H5 的跳转结果判断支付成功。

建议先在 Android 端记录表单提交后的跳转 URL。如果已经出现 alipays:// 或 intent://,补上协议拦截和 Intent 唤起处理;如果没有发生任何跳转,再检查后端返回的表单,以及 H5 插入和提交表单的逻辑。

备注:内容仅供参考。