PAYATHON 2026

Android WebView 在华为 MATE PRO 40 上无法调起支付宝

支付老李

结论

这类问题通常不是”华为 MATE 40 Pro 不支持支付宝”,而是支付跳转链路在特定系统版本、WebView 版本或审核环境下遇到了兼容性问题。

建议先排查以下几项:

  1. 是否处理了 alipays://、alipay://、intent:// 等实际跳转形式,而不只是判断字符串是否以 "alipay" 开头。
  2. 是否同时实现了新旧两个 shouldOverrideUrlLoading() 回调,并正确处理返回值。
  3. Android 11 及以上系统是否因为”应用包可见性”限制,把已经安装的支付宝误判为未安装。
  4. 审核设备是否安装并启用了支付宝,是否使用了应用分身、隐私空间或受管控账户。
  5. 支付页面是否通过 window.open()、新窗口、302 重定向或中间页拉起支付宝。
  6. 是否捕获后忽略了 ActivityNotFoundException、URISyntaxException 等异常,导致审核人员点击后只看到”没有反应”。

只判断 URI 是否以 "alipay" 开头,覆盖不了所有支付跳转情况。

推荐的 WebView 跳转处理方式

不要只做简单的前缀匹配。可以先放行普通 HTTP 链接,再把其他外部协议交给系统处理。

private boolean handleUrl(Context context, String url) {
    if (url == null || url.isEmpty()) {
        return false;
    }

    Uri uri = Uri.parse(url);
    String scheme = uri.getScheme();

    // 普通网页继续由 WebView 加载
    if ("http".equalsIgnoreCase(scheme)
            || "https".equalsIgnoreCase(scheme)) {
        return false;
    }

    try {
        Intent intent;

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

            // 防止外部页面借此启动不必要的内部组件
            intent.addCategory(Intent.CATEGORY_BROWSABLE);
            intent.setComponent(null);
            intent.setSelector(null);

            try {
                context.startActivity(intent);
            } catch (ActivityNotFoundException e) {
                String fallbackUrl =
                        intent.getStringExtra("browser_fallback_url");

                if (fallbackUrl != null
                        && (fallbackUrl.startsWith("https://")
                        || fallbackUrl.startsWith("http://"))) {
                    return false;
                }

                throw e;
            }
        } else {
            intent = new Intent(Intent.ACTION_VIEW, uri);
            intent.addCategory(Intent.CATEGORY_BROWSABLE);
            context.startActivity(intent);
        }

        return true;
    } catch (ActivityNotFoundException e) {
        // 设备未安装可处理该协议的应用,或相关组件被禁用
        showPayError("未检测到可用的支付宝,请确认支付宝已安装并启用");
        return true;
    } catch (URISyntaxException | SecurityException e) {
        // 建议同时记录原始 URL、系统版本和 WebView 版本
        reportPayLaunchError(url, e);
        showPayError("无法打开支付宝,请稍后重试");
        return true;
    }
}

还要同时实现新旧两个 shouldOverrideUrlLoading() 回调,以兼容不同系统和 WebView 的行为:

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

    @SuppressWarnings("deprecation")
    @Override
    public boolean shouldOverrideUrlLoading(
            WebView view,
            String url
    ) {
        return handleUrl(view.getContext(), url);
    }
});

返回值的含义需要特别注意:

  • 返回 true,表示应用已经处理该 URL,WebView 不应继续加载。
  • 返回 false,表示该 URL 仍由 WebView 加载。

如果已经启动支付宝却返回 false,部分 WebView 版本还会继续尝试加载自定义协议,可能出现错误页、白屏或跳转被覆盖。

排查 Android 11 的应用包可见性

MATE 40 Pro 的审核设备可能运行 Android 11 或更高版本。从 Android 11 开始,系统会限制应用查询其他已安装应用。

如果代码在跳转前调用了以下方法:

getPackageManager().getPackageInfo(...);
resolveActivity(...);
queryIntentActivities(...);

即使设备已经安装支付宝,也可能因为应用没有声明查询范围而返回”未安装”,或者查询不到对应的 Activity。可以根据实际查询方式,在 AndroidManifest.xml 中添加 <queries>:

<manifest xmlns:android="http://schemas.android.com/apk/res/android">

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

        <intent>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.BROWSABLE" />
            <data android:scheme="alipays" />
        </intent>
    </queries>

    <application>
        ...
    </application>
</manifest>

<queries> 主要影响”查询是否存在”的逻辑。直接调用 startActivity() 和提前使用 resolveActivity() 检查并不完全相同。因此,不建议仅凭一次查询结果阻止支付跳转。更稳妥的做法是直接尝试启动,并捕获 ActivityNotFoundException。

支付宝的包名、Scheme 和接入方式,应以当前使用的支付宝官方 SDK 或支付产品文档为准,不要只依赖硬编码字符串。

检查真实跳转 URL

代码判断字符串以 "alipay" 开头,不等于支付页面最终一定会产生这种 URL。实际链路中可能出现:

alipays://...
alipay://...
intent://...
https://...

跳转也可能先经过多个 HTTP 302 重定向,最后才进入自定义 Scheme。建议记录以下信息:

  • 用户点击支付按钮时的页面 URL。
  • shouldOverrideUrlLoading() 收到的完整 URL。
  • Scheme、Host 和重定向次数。
  • 是否执行了 startActivity()。
  • 捕获到的异常类型和异常信息。
  • Android 版本、WebView 版本和支付宝版本。
  • 支付页面返回的订单或接口错误码,但不要记录完整支付参数、Token 或签名。

如果日志只写”进入了支付方法”,仍然无法判断问题出在网页、WebView,还是系统 Intent 阶段。

检查新窗口和 JavaScript 跳转

部分商城支付页不会直接修改当前页面地址,而是调用:

window.open(payUrl)

或者使用:

<a href="..." target="_blank">

遇到这种情况,URL 可能进入 WebChromeClient.onCreateWindow(),而不是预期中的 shouldOverrideUrlLoading()。如果商城确实通过新窗口跳转,需要补充相应处理:

webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setSupportMultipleWindows(true);
webView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);

webView.setWebChromeClient(new WebChromeClient() {
    @Override
    public boolean onCreateWindow(
            WebView view,
            boolean isDialog,
            boolean isUserGesture,
            Message resultMsg
    ) {
        WebView newWebView = new WebView(view.getContext());

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

            @SuppressWarnings("deprecation")
            @Override
            public boolean shouldOverrideUrlLoading(
                    WebView view,
                    String url
            ) {
                return handleUrl(view.getContext(), url);
            }
        });

        WebView.WebViewTransport transport =
                (WebView.WebViewTransport) resultMsg.obj;
        transport.setWebView(newWebView);
        resultMsg.sendToTarget();
        return true;
    }
});

是否要开启多窗口,需要根据商城页面的具体实现决定。如果可以修改 H5,更推荐在当前页面完成跳转,以减少临时 WebView 引起的生命周期、Cookie 和内存问题。

检查审核环境

审核报告只能说明支付在特定测试环境中没有成功拉起,不能直接证明这是机型硬件问题。还需要确认:

  • 审核设备是否安装了支付宝。
  • 支付宝是否被停用、冻结或限制后台启动。
  • 测试账号是否处于隐私空间、访客模式或工作资料中。
  • 应用和支付宝是否位于不同的用户空间。
  • 是否使用了应用分身。
  • 是否出现过系统弹窗,但被测试人员拒绝。
  • 网络环境是否导致支付中间页未能取得有效跳转地址。
  • 测试订单是否失效、重复支付或被风控拦截。

找不到可处理该协议的应用时,至少要向用户显示明确提示,不能让按钮点击后静默失败。

还应检查的 WebView 配置

如果支付页面本身没有正常加载,流程可能根本没有执行到拉起支付宝这一步。可以继续检查:

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

其中,setCookieEnabled() 不是 WebSettings 的方法。Cookie 应通过 CookieManager 配置:

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

是否必须开启第三方 Cookie,要根据商城的登录和支付链路决定。此外还要检查:

  • HTTPS 页面中是否加载了 HTTP 资源。
  • H5 是否依赖第三方 Cookie 或本地存储。
  • 是否存在证书错误,以及 onReceivedSslError() 是否处理不当。
  • Release 包是否因为混淆、渠道配置、签名或域名环境不同,表现与本地测试包不一致。
  • 华为市场审核包是否连接正式环境,而本地测试使用测试环境。
  • 支付返回页是否被错误的应用深链配置拦截。

不要通过无条件调用 handler.proceed() 绕过 HTTPS 证书错误。这会带来严重的安全风险,也可能影响应用审核。

没有真机时的验证办法

可以先制作一个最小测试页面,分别测试以下链接:

<a href="alipays://platformapi/startapp">测试 alipays</a>
<a href="intent://example#Intent;scheme=alipays;end">测试 intent</a>
<a href="https://example.com">测试 HTTPS</a>

这些示例只用于验证 WebView 回调和 Intent 分支,不代表有效的支付宝业务地址。

测试时应使用与审核包完全相同的 Release 构建,再通过云真机、远程设备测试服务,或能提供该机型的测试人员复现。复现过程中,应重点获取完整的跳转 URL 和异常日志,而不只是录制一段”点击无反应”的视频。

综合现有信息,建议优先检查 intent:// 是否遗漏、Android 11 包可见性判断是否误判、是否只实现了一个 shouldOverrideUrlLoading() 回调,以及支付页是否通过新窗口发起跳转。这几项最容易造成”手头设备正常,但特定审核设备无法拉起”的差异。

备注:内容仅供参考。