Android WebView无法加载支付URL但浏览器可正常加载问题求助
问题描述
尝试在Android WebView中加载一个支付页面(银行卡信息输入界面),该页面在浏览器中可正常打开,但WebView里无法显示内容。日志显示onPageStarted()和onPageFinished()已触发,但未捕获到onReceivedError()、onReceivedSslError()等错误信息,参考相关解决方案后问题仍未解决。
相关代码
加载支付页面的核心方法
private void loadPaymentURL(){ webView.setWebChromeClient(new WebChromeClient()); webView.getSettings().setAllowFileAccessFromFileURLs(true); webView.getSettings().setAllowUniversalAccessFromFileURLs(true); webView.clearCache(true); webView.clearHistory(); webView.getSettings().setAllowContentAccess(true); webView.getSettings().setDomStorageEnabled(true); webView.getSettings().setJavaScriptEnabled(true); // enable javascript webView.getSettings().setBuiltInZoomControls(true); webView.getSettings().setSupportZoom(true); webView.getSettings().setLoadWithOverviewMode(true); webView.getSettings().setUseWideViewPort(true); webView.getSettings().setDisplayZoomControls(false); webView.getSettings().setAllowFileAccess(false); webView.getSettings().setLoadsImagesAutomatically(true); webView.getSettings().setDatabaseEnabled(true); webView.setWebViewClient(new MyWebViewClient()); Log.e("WEBVIEW", "PaymentURL : "+paymentUrl); try { paymentUrl = getFinalURL(paymentUrl); }catch (Exception e){} Log.e("WEBVIEW", "FinalURL : "+paymentUrl); webView.loadUrl(paymentUrl); }
获取最终跳转URL的方法
public static String getFinalURL(String url) throws IOException { HttpURLConnection con = (HttpURLConnection) new URL(url).openConnection(); con.setInstanceFollowRedirects(false); con.connect(); con.getInputStream(); if (con.getResponseCode() == HttpURLConnection.HTTP_MOVED_PERM || con.getResponseCode() == HttpURLConnection.HTTP_MOVED_TEMP) { String redirectUrl = con.getHeaderField("Location"); return getFinalURL(redirectUrl); } return url; }
自定义WebViewClient实现
private class MyWebViewClient extends WebViewClient { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { view.getSettings().setJavaScriptEnabled(true); return true; } @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { Log.e("WEBVIEW", "onPageStarted() : "+url); progressLayout.setVisibility(View.VISIBLE); } @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); Log.e("WEBVIEW", "onPageFinished() : "+url); progressLayout.setVisibility(View.GONE); } @Override public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) { Log.e("WEBVIEW", "onReceivedError1() : "+error); view.goForward(); } @Override public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { Log.e("WEBVIEW", "onReceivedError2() URL: "+failingUrl+" , Description:"+description); view.goForward(); progressLayout.setVisibility(View.GONE); } @Override public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { Log.e("WEBVIEW", "onReceivedSslError() : "+error.toString()); //progressLayout.setVisibility(View.GONE); view.goForward(); } }
解决方案建议
修复URL跳转拦截逻辑:当前
shouldOverrideUrlLoading返回true会阻止WebView加载内部跳转的页面,应修改为仅拦截外部URL,内部跳转交给WebView处理:@Override public boolean shouldOverrideUrlLoading(WebView view, String url) { // 仅拦截非支付域名的URL,跳转外部浏览器打开 if (!url.startsWith("https://pay.expresspay.sa")) { Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); startActivity(intent); return true; } return false; }同时建议重写API 24+的
shouldOverrideUrlLoading(WebView view, WebResourceRequest request)方法以适配新版本系统。统一User-Agent设置:部分支付网站会根据User-Agent判断设备类型,手动设置和移动端浏览器一致的User-Agent:
webView.getSettings().setUserAgentString("Mozilla/5.0 (Linux; Android 10; SM-G973F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.120 Mobile Safari/537.36");启用第三方Cookie与混合内容支持:支付页面可能依赖第三方Cookie和混合内容加载,添加以下设置:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { webView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW); CookieManager.getInstance().setAcceptThirdPartyCookies(webView, true); }添加JavaScript错误日志监听:通过
WebChromeClient捕获页面的JS错误,排查页面渲染失败原因:webView.setWebChromeClient(new WebChromeClient() { @Override public boolean onConsoleMessage(ConsoleMessage consoleMessage) { Log.e("WEBVIEW_JS", consoleMessage.message() + " -- 行号: " + consoleMessage.lineNumber() + " 来源: " + consoleMessage.sourceId()); return super.onConsoleMessage(consoleMessage); } });移除冲突权限设置:代码中同时开启了
setAllowFileAccessFromFileURLs(true)和setAllowFileAccess(false),二者存在权限冲突,支付页面通常不需要文件访问权限,建议移除setAllowFileAccessFromFileURLs和setAllowUniversalAccessFromFileURLs的设置。
内容的提问来源于stack exchange,提问作者SHIDHIN TS

