Android WebView无法加载HTTPS URL。

109
public void onCreate(Bundle savedInstance)
{       
    super.onCreate(savedInstance);
    setContentView(R.layout.show_voucher);
    webView=(WebView)findViewById(R.id.webview);
    webView.getSettings().setJavaScriptEnabled(true);
    webView.getSettings().setBuiltInZoomControls(true);
    String url ="https://www.paymeon.com/Vouchers/?v=%C80%8D%B1x%D9%CFqh%FA%84%C35%0A%1F%CE&iv=%25%EE%BEi%F4%DAT%E1"
    //webView.loadUrl(url); // Not Working... Showing blank
    webView.loadUrl("http://www.yahoo.com"); // its working    
}
当我尝试在WebBView中加载一个URL时,它只显示一个空白屏幕。如果我加载Google.com或yahoo.com的话就正常工作。

1
现在它正在工作,我已经检查过了。如果还不行,请再次检查,然后将以下代码添加到您的代码中:webView.getSettings().setUseWideViewPort(true); webView.getSettings().setLoadWithOverviewMode(true); - ilango j
17个回答

172

请访问此链接:

将此覆盖方法添加到您的WebViewClient实现中。您需要使用Android SDK 2.2(API级别8)或更高版本进行编译。该方法从2.2版(API级别8)开始出现在公共SDK中,但我们已经在运行2.1、1.6和1.5设备上测试过它,它也可以在这些设备上工作(因此显然一直存在这个行为)。

 @Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
    handler.proceed(); // Ignore SSL certificate errors
}

这会对你有所帮助。


3
讨论中的最后一篇回复效果很好,非常感谢。 - Bill Lahti
68
安全警告:请注意,这样做完全违背了首次使用SSL的初衷。 - ereOn
9
请不要这样做。这是不安全的并且在Play Store中是不允许的。 - Antimony
41
谷歌现在正在向实施以上解决方案的人发送电子邮件: 本电子邮件末尾列出的您的应用程序存在一个不安全的 WebViewClient.onReceivedSslError 处理程序的实现。具体来说,该实现忽略了所有 SSL 证书验证错误,使您的应用程序容易受到中间人攻击的威胁。 存在暴露用户面临危险的漏洞的应用程序可能被视为违反《内容政策》和《开发者分发协议》第4.4节的危险产品。 - Gustavo
6
有人知道如何解决谷歌安全警告吗?如果知道,请告诉我,因为我也遇到了这个问题。 - Pratik Tank
显示剩余5条评论

53

fargth回答正确后,下面是一个可能有帮助的小代码示例。

首先创建一个扩展了WebViewClient类的类,并将其设置为忽略SSL错误:

// SSL Error Tolerant Web View Client
private class SSLTolerentWebViewClient extends WebViewClient {

            @Override
            public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
                handler.proceed(); // Ignore SSL certificate errors
            }

}

然后,使用您在OnCreate()方法中初始化的Web视图对象,将其WebView客户端设置为覆盖类的实例:

 mWebView.setWebViewClient(
                new SSLTolerentWebViewClient()
        );

2
这会触发 Google 安全警告:WebViewClient.onReceivedSslError 处理程序的不安全实现。你知道如何解决吗? - Pratik Tank
3
谷歌在应用商店中将该应用标记为不安全,如果没有 SSL,如何解决? - Ajay Pandya
不要使用Super方法 - super.onReceivedSslError(view, handler, error); - Atul Bhardwaj
它可以用于普通网页,但当我尝试加载YouTube视频的iframe时,它无法正常工作。 - babbin tandukar

45

为了正确处理SSL证书验证并避免应用程序根据最新的安全政策被Google拒绝,请更改您的代码,每当服务器呈现的证书符合您的期望时调用SslErrorHandler.proceed(),否则调用SslErrorHandler.cancel()。

例如,我添加了一个警示对话框,以确保用户已确认,并且似乎Google不再显示警告。

    @Override
    public void onReceivedSslError(WebView view, final SslErrorHandler handler, SslError error) {
    final AlertDialog.Builder builder = new AlertDialog.Builder(this);
    String message = "SSL Certificate error.";
        switch (error.getPrimaryError()) {
            case SslError.SSL_UNTRUSTED:
                message = "The certificate authority is not trusted.";
                break;
            case SslError.SSL_EXPIRED:
                message = "The certificate has expired.";
                break;
            case SslError.SSL_IDMISMATCH:
                message = "The certificate Hostname mismatch.";
                break;
            case SslError.SSL_NOTYETVALID:
                message = "The certificate is not yet valid.";
                break;
        }
        message += " Do you want to continue anyway?";

        builder.setTitle("SSL Certificate Error");
        builder.setMessage(message);
    builder.setPositiveButton("continue", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            handler.proceed();
        }
    });
    builder.setNegativeButton("cancel", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            handler.cancel();
        }
    });
    final AlertDialog dialog = builder.create();
    dialog.show();
}

这些更改后将不会显示警告。


1
如果我从代码实现中删除了onReceivedSslError代码块,会发生什么? - Vivek Sinha
1
@VivekSinha 默认情况下,它将调用 handler.cancel();。 - Anant Shah
3
但是Google仍然因同样的原因拒绝了我的应用。为什么? - Vivek Sinha
1
@VivekSinha 找到关于应用在Play商店启动的解决方案了吗? - Kesha
2
我按照建议实现了onReceivedSslError回调函数。之后应用程序成功发布。 - Vivek Sinha
如果应用程序没有包含足够的证书有效性检查,例如仅检查getPrimaryError的返回值是不足以确定证书的有效性,那么该应用程序可能会被标记。 - Yoda066

13

重写onReceivedSslError并去除

super.onReceivedSslError(view, handler, error)

为解决Google安全性问题:

setDomStorageEnabled(true);

完整代码如下:

webView.enableJavaScript();
webView.getSettings().setDomStorageEnabled(true); // Add this
webView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
webView.setWebViewClient(new WebViewClient(){
        @Override
        public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
            // DO NOT CALL SUPER METHOD
            super.onReceivedSslError(view, handler, error);
        }
    });

非常感谢你。删除super.onReceivedSslError(view, handler, error)对我有用。 - Däñish Shärmà

11

移除下面的代码,它会正常工作。

 super.onReceivedSslError(view, handler, error);

太好了,它对我起作用了。你能解释一下它是如何工作的吗? - Arth Tilva
3
“默认行为是取消加载”。通过调用super,您在其余方法之前调用了该默认行为。 - Josh Laird

8

复制并粘贴您的代码行,相信我它会起作用 :) 我在想,您遇到了ssl错误。如果您在onReceivedSslError方法中使用override并删除super它的super方法。只需编写handler.proceed(),错误将得到解决。

    webView.setWebChromeClient(new WebChromeClient() {
        public void onProgressChanged(WebView view, int progress) {

            activity.setTitle("Loading...");
            activity.setProgress(progress * 100);

            if (progress == 100)
                activity.setTitle(getResources().getString(R.string.app_name));
        }
    });

    webView.setWebViewClient(new WebViewClient() {
        @Override
        public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
            Log.d("Failure Url :" , failingUrl);
        }

        @Override
        public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
            Log.d("Ssl Error:",handler.toString() + "error:" +  error);
            handler.proceed();
        }

        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            view.loadUrl(url);
            return true;
        }
    });
    webView.getSettings().setJavaScriptEnabled(true);
    webView.getSettings().setLoadWithOverviewMode(true);
    webView.getSettings().setUseWideViewPort(true);
    webView.getSettings().setDomStorageEnabled(true);
    webView.loadUrl(Constant.VIRTUALPOS_URL + "token=" + Preference.getInstance(getContext()).getToken() + "&dealer=" + Preference.getInstance(getContext()).getDealerCode());

谢谢。在onReceivedSslError中调用handler.proceed()让我度过了难关。 - Tam Huynh
2
如果你这样做(现在是2019年7月),谷歌应用商店将会拒绝你的应用程序。 - Alp Altunel
我在Google Play上有太多的应用程序,但是仍然有一些应用被拒绝了。 - ozanurkan
2
将拒绝2020年1月及以后的申请。 - John Ruban Singh

6
为了解决谷歌安全问题,请执行以下步骤:

将代码行移到文件顶部:

import android.webkit.SslErrorHandler;
import android.net.http.SslError;

代码:

class SSLTolerentWebViewClient extends WebViewClient {
    @Override
    public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
        if (error.toString() == "piglet")
            handler.cancel();
        else
            handler.proceed(); // Ignore SSL certificate errors
    }
}

5
我是Android的新手。这个应该放在哪里? :) - Gediminas Šukys

6

我按照上面的答案进行了尝试,但似乎对我没有用。下面的代码在我集成通常是https请求的付款网关时为我解决了问题:

public class MainActivity extends Activity {

    WebView webView;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        webView = (WebView) findViewById(R.id.webView1);
        WebSettings settings = webView.getSettings();
        settings.setJavaScriptEnabled(true);
        settings.setDomStorageEnabled(true);
        webView.setWebViewClient(new MyWebViewClient());
        String postData = "amount=1000&firstname=mtetno&email=mttee@gmail.com&phone=2145635784&productinfo=android&surl=success.php"
                + "&furl=failure.php&lastname=qwerty&curl=dsdsd.com&address1=dsdsds&address2=dfdfd&city=dsdsds&state=dfdfdfd&"
                + "country=fdfdf&zipcode=123456&udf1=dsdsds&udf2=fsdfdsf&udf3=jhghjg&udf4=fdfd&udf5=fdfdf&pg=dfdf";
        webView.postUrl(
                "http://host/payment.php",
                EncodingUtils.getBytes(postData, "BASE64"));

    }

    private class MyWebViewClient extends WebViewClient {
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            webView.loadUrl(url);
            return true;
        }

        @Override
        public void onReceivedSslError(WebView view, SslErrorHandler handler,
                SslError error) {
            handler.proceed();
        }
    }
}

以上代码在webview中进行了一次POST请求,并重定向到支付网关。

settings.setDomStorageEnabled(true);设置为true对我很有帮助,希望这可以帮到你。


2
此解决方案完全禁用证书验证,使您容易受到中间人攻击。这是您绝不能做的事情,特别是对于支付网关。 - Dirbaio
起初,WebView 并没有加载内容,只显示了页面的背景图片。但是当我添加了 webview.getSettings.setDomStorageEnabled(true); 后,它就神奇地正常工作了。也许该网页使用了某种 HTML 5 API,因此启用 DomStorage 对我有用。 - Ishant Sagar
handler.proceed() 绕过 SSL。 - John Ruban Singh
什么是Encodingutil.getbyte? - Akash kumar

6
为了处理SSL url,需要使用WebViewClient类中的onReceivedSslError()方法。以下是一个示例:
 webview.setWebViewClient(new WebViewClient() {
              ...
              ...
              ...

            @Override
            public void onReceivedSslError(WebView view, final SslErrorHandler handler, SslError error) {
                String message = "SSL Certificate error.";
                switch (error.getPrimaryError()) {
                    case SslError.SSL_UNTRUSTED:
                        message = "The certificate authority is not trusted.";
                        break;
                    case SslError.SSL_EXPIRED:
                        message = "The certificate has expired.";
                        break;
                    case SslError.SSL_IDMISMATCH:
                        message = "The certificate Hostname mismatch.";
                        break;
                    case SslError.SSL_NOTYETVALID:
                        message = "The certificate is not yet valid.";
                        break;
                }
                message += "\"SSL Certificate Error\" Do you want to continue anyway?.. YES";

                handler.proceed();
            }

        });

您可以在此处查看完整示例: https://github.com/Jorgesys/Android-WebView-Logging

enter image description here


4
如果您想在Google Play商店之外使用APK,例如私人解决方案,则以下解决方案可能有效:
    @Override
    public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
        /*...*/
        handler.proceed();
    }

如果您想增加额外的可选安全层,可以尝试使用证书固定。但我认为对于私人或内部使用来说,这并不是必要的。
如果您计划在Google Play商店上发布应用程序,则应避免使用@Override onReceivedSslError(...){...},特别是使用handler.proceed()。 Google会发现这段代码,并肯定会拒绝您的应用程序,因为使用handler.proceed()的解决方案将抑制所有内置的安全机制

仅仅因为浏览器没有对您的https连接进行投诉,并不意味着SSL证书本身是值得信任的!

在我的情况下,SSL证书链已断裂。您可以使用SSL Checker或更详细的SSLLabs快速测试此类问题。但请不要问我这是如何发生的。我完全不知道。
无论如何,在重新安装SSL证书之后,有关“WebView中未经信任的SSL证书”的所有错误最终都消失了。 我还删除了onReceivedSslError(...)的@Override并摆脱了handler.proceed(),然后我的应用程序就不再被Google Play Store拒绝了(再次)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接