精华内容
下载资源
问答
  • 最近做无线WiFi的时候,在最后认证成功的时候会弹出一个广告页,于是用webview去加载了一下,结果没反应,打印url出来看了一下,发现是https格式的,在使用WebView加载https资源文件时,如果认证证书不被Android认可...
  • 主要介绍了详解android 用webview加载网页(https和http),详细的介绍了两个错误的解决方法,有兴趣的可以了解一下
  • HTTPS简介 HTTPS(Hyper Text Transfer Protocol Secure),是一种基于SSL/TLS的HTTP,所有的HTTP数据都是在SSL/TLS协议封装之上进行传输的。HTTPS协议是在HTTP协议的基础上,添加了SSL/TLS握手以及数据加密传输,也...

    HTTPS简介

    HTTPS(Hyper Text Transfer Protocol Secure),是一种基于SSL/TLS的HTTP,所有的HTTP数据都是在SSL/TLS协议封装之上进行传输的。HTTPS协议是在HTTP协议的基础上,添加了SSL/TLS握手以及数据加密传输,也属于应用层协议。所以,研究HTTPS协议原理,最终其实就是研究SSL/TLS协议。

    SSL/TLS协议

    不使用SSL/TLS的HTTP通信,就是不加密的通信,所有的信息明文传播,带来了三大风险:

    窃听风险:第三方可以获知通信内容。

    篡改风险:第三方可以修改通知内容。

    冒充风险:第三方可以冒充他人身份参与通信。

    SSL/TLS协议是为了解决这三大风险而设计的,希望达到:

    所有信息都是加密传输,第三方无法窃听。

    具有校验机制,一旦被篡改,通信双方都会立刻发现。

    配备身份证书,防止身份被冒充。

    HTTPS基本运行过程

    SSL/TLS协议的基本思路是采用公钥加密法,也就是说,客户端先向服务器端索要公钥,然后用公钥加密信息,服务器收到密文后,用自己的私钥解密,这就是非对称加密。但是这里需要了解两个问题的解决方案。

    如何保证公钥不被篡改?
    解决方法:将公钥放在数字证书中。只要证书是可信的,公钥就是可信的。

    公钥加密计算量太大,如何减少耗用的时间?
    解决方法:每一次对话(session),客户端和服务器端都生成一个“对话密钥”(session key),用它来加密信息。由于“对话密钥”是对称加密,所以运算速度非常快,而服务器公钥只用于加密“对话密钥”本身,这样就减少了加密运算的消耗时间。

    因此,SSL/TLS协议的基本过程是这样的:

    客户端向服务器端索要并验证公钥。

    双方协商生成“对话密钥”。

    双方采用“对话密钥”进行加密通信。

    上面过程的前两步,又称为“握手阶段”。


    客户端发起HTTPS请求

    服务端的配置
    采用HTTPS协议的服务器必须要有一套数字证书,可以是自己制作或者CA证书。区别就是自己颁发的证书需要客户端验证通过,才可以继续访问,而使用CA证书则不会弹出提示页面。这套证书其实就是一对公钥和私钥。公钥给别人加密使用,私钥给自己解密使用。

    传送证书
    这个证书其实就是公钥,只是包含了很多信息,如证书的颁发机构,过期时间等。

    客户端解析证书
    这部分工作是有客户端的TLS来完成的,首先会验证公钥是否有效,比如颁发机构,过期时间等,如果发现异常,则会弹出一个警告框,提示证书存在问题。如果证书没有问题,那么就生成一个随即值,然后用证书对该随机值进行加密。

    传送加密信息
    这部分传送的是用证书加密后的随机值,目的就是让服务端得到这个随机值,以后客户端和服务端的通信就可以通过这个随机值来进行加密解密了。

    服务端解密信息
    服务端用私钥解密后,得到了客户端传过来的随机值(私钥),然后把内容通过该值进行对称加密。所谓对称加密就是,将信息和私钥通过某种算法混合在一起,这样除非知道私钥,不然无法获取内容,而正好客户端和服务端都知道这个私钥,所以只要加密算法够彪悍,私钥够复杂,数据就够安全。

    传输加密后的信息
    这部分信息是服务端用私钥加密后的信息,可以在客户端被还原。

    客户端解密信息
    客户端用之前生成的私钥解密服务端传过来的信息,于是获取了解密后的内容。

    整个握手过程第三方即使监听到了数据,也束手无策。

    HTTP和HTTPS的区别

    https协议需要到CA申请证书或自制证书。
    http的信息是明文传输,https则是具有安全性的ssl加密。
    http是直接与TCP进行数据传输,而https是经过一层SSL(OSI表示层),用的端口也不一样,前者是80(需要国内备案),后者是443。
    http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。

    Android实现HTTPS通信

    CA认证的数字证书网站

    以百度的https网址(https://m.baidu.com/)为例,示例源码如下:

    public void startHttpsConnection() {
        HttpsURLConnection httpsURLConnection = null;
        BufferedReader reader = null;
        try {
            URL url = new URL("https://m.baidu.com/");
            httpsURLConnection = (HttpsURLConnection) url.openConnection();
            httpsURLConnection.setConnectTimeout(5000);
            httpsURLConnection.setDoInput(true);
            httpsURLConnection.setUseCaches(false);
            httpsURLConnection.connect();
    
            reader = new BufferedReader(new InputStreamReader(httpsURLConnection.getInputStream()));
            StringBuilder sBuilder = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                sBuilder.append(line);
            }
            Log.e("TAG", "Wiki content=" + sBuilder.toString());
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (httpsURLConnection != null) {
                httpsURLConnection.disconnect();
            }
    
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    由于百度是有CA授权的数字证书,所以这里我们就是简单的使用HttpsUrlConnection对其进行访问,就实现了HTTPS通信。

    自签名的数字证书网站

    由于CA认证是需要收费的,所以有些网站为了节约成本,采用自签名的数字证书,比如,注明的购票网站12306目前依然是这么干的。如果我们用上述代码访问自签名的网站会有什么问题呢? 访问自签名证书的网站,Android直接会throw SSLHandshakeException,原因就是12306的数字证书不被Android系统的信任。想解决这个问题,有如下几种方法。

    让HttpsURLConnection信任所有的CA证书

    1. 实现X509TrustManager接口,在接口实现中跳过客户端和服务器端认证。

    public class TrustAllCertsManager implements X509TrustManager {
        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType)
                throws CertificateException {
            // Do nothing -> accept any certificates
        }
    
        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType)
                throws CertificateException {
            // Do nothing -> accept any certificates
        }
    
        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[0];
        }
    }

    2. 实现HostnameVerifier接口,不进行url和服务器主机名的验证。

    public class VerifyEverythingHostnameVerifier implements HostnameVerifier {
        @Override
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    }

    3. 基于上面实现的TrustAllCertsManager修改HttpsURLConnection类的默认SSL socket factory。
    TrustManager[] trustManager = new TrustManager[] {new TrustEverythingTrustManager()};
    SSLContext sslContext = null;
    try {
        sslContext = SSLContext.getInstance("SSL");
        sslContext.init(null, trustManager, new java.security.SecureRandom());
    } catch (NoSuchAlgorithmException e) {
        // do nothing
    }catch (KeyManagementException e) {
        // do nothing
    }
    HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
    4. 实例化HttpsUrlConnection,并设置HostnameVerifier为上面实现的VerifyEverythingHostnameVerifier

    httpsURLConnection = (HttpsURLConnection) url.openConnection();
    httpsURLConnection.setHostnameVerifier(new VerifyEverythingHostnameVerifier());
    但是以上方法存在严重的安全漏洞,因为默认相信一切证书,其实是忽略了证书验证。比如注明的中间人攻击: 虽然上述方案使用了HTTPS,客户端和服务器端的通信内容得到了加密,嗅探程序无法得到传输的内容,但是无法抵挡“中间人攻击”。例如,在内网配置一个DNS,把目标服务器域名解析到本地的一个地址,然后在这个地址上使用一个中间服务器作为代理,它使用一个假的证书与客户端通讯,然后再由这个代理服务器作为客户端连接到实际的服务器,用真的证书与服务器通讯。这样所有的通讯内容都会经过这个代理,而客户端不会感知,这是由于客户端不校验服务器公钥证书导致的。

    让HttpsURLConnection信任指定的CA证书

    为了防止上面方案可能导致的“中间人攻击”,我们可以事先下载服务器端公钥证书,然后将公钥证书编译到Android应用中,由应用自己来验证证书。也就是我们来教会HttpsUrlConnection来认识特定的自签名网站。还是以12306网站为例。

    1. 下载12306的服务器公钥证书

    12306公钥证书下载地址:12306根证书下载地址

    2. 将下载的证书放到应用的assets目录下.

    app->src->main->assets->srca.cer
    (ps:使用Android Studio的同学需要特别注意默认asserts目录的位置)。

    3. 构造特定的TrustManager[]数组.

    private TrustManager[] createTrustManager() {
        BufferedInputStream cerInputStream = null;
        try {
            // 获取客户端存放的服务器公钥证书
            cerInputStream = new BufferedInputStream(getAssets().open("srca.cer"));
            // 根据公钥证书生成Certificate对象
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            Certificate ca = cf.generateCertificate(cerInputStream);
            Log.e("TAG", "ca=" + ((X509Certificate) ca).getSubjectDN());
    
            // 生成包含当前CA证书的keystore
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(null, null);
            keyStore.setCertificateEntry("ca", ca);
    
            // 使用包含指定CA证书的keystore生成TrustManager[]数组
            String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
            tmf.init(keyStore);
            return tmf.getTrustManagers();
        } catch (CertificateException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (KeyStoreException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } finally {
            if (cerInputStream != null) {
                try {
                    cerInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    4. 初始化SSLContext.

    SSLContext sc = SSLContext.getInstance("SSL");
    TrustManager[] trustManagers = createTrustManager();
    if (trustManagers == null) {
        Log.e("TAG", "tmf create failed!");
        return;
    }
    sc.init(null, trustManagers, new SecureRandom());
    URL url = new URL("https://kyfw.12306.cn/otn/login/init");
    HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

    Retrofit支持HTTPS

    和普通http客户端请求支持https一样,步骤如下:

    1 CertificateFactory 得到Context.getSocketFactory
    2 添加证书源文件
    3 绑定到okhttpClient
    4设置okhttpClient到retrofit中

    证书同样可以设置到okhttpclient中,我们可以把证书放到raw路径下

    SLSocketFactory sslSocketFactory =getSSLSocketFactory_Certificate(context,"BKS", R.raw.XXX);
    绑定证书:

    protected static SSLSocketFactory getSSLSocketFactory(Context context, int[] certificates) {
    
    if (context == null) {
        throw new NullPointerException("context == null");
    }
    
    CertificateFactory certificateFactory;
    try {
        certificateFactory = CertificateFactory.getInstance("X.509");
        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        keyStore.load(null, null);
    
        for (int i = 0; i < certificates.length; i++) {
            InputStream certificate = context.getResources().openRawResource(certificates[i]);
            keyStore.setCertificateEntry(String.valueOf(i), certificateFactory.generateCertificate(certificate));
    
            if (certificate != null) {
                certificate.close();
            }
        }
        SSLContext sslContext = SSLContext.getInstance("TLS");
        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        trustManagerFactory.init(keyStore);
        sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());
       return sslContext.getSocketFactory();

    构建HostnameVerifier:

    protected static HostnameVerifier getHostnameVerifier(final String[] hostUrls) {
    
        HostnameVerifier TRUSTED_VERIFIER = new HostnameVerifier() {
    
            public boolean verify(String hostname, SSLSession session) {
                boolean ret = false;
                for (String host : hostUrls) {
                    if (host.equalsIgnoreCase(hostname)) {
                        ret = true;
                    }
                }
                return ret;
            }
        };
    
    return TRUSTED_VERIFIER;

    设置setSocketFactory:

    okhttpBuilder.socketFactory(HttpsFactroy.getSSLSocketFactory(context, certificates));
    certificates 是你raw下证书源ID, int[] certificates = {R.raw.myssl}

    设置setNameVerifier:

    okhttpBuilder.hostnameVerifier(HttpsFactroy.getHostnameVerifier(hosts));

    hosts是你的host数据 列如 String hosts[]`= {“https//:aaaa,com”, “https//:bbb.com”}

    实现自定义 添加到Retrofit:

    okHttpClient = okhttpBuilder.build(); 
      Retrofit retrofit = new Retrofit.Builder() .client(okHttpClient) .build();
    如果信任所有https请求,
    可以直接将OkHttpClient的HostnameVerifier设置为false

    OkHttpClient client = new OkHttpClient();
    
        client.setHostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String s, SSLSession sslSession) {
                return true;
            }
        });
        TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
            @Override
            public void checkClientTrusted(
                    java.security.cert.X509Certificate[] x509Certificates,
                    String s) throws java.security.cert.CertificateException {
            }
    
            @Override
            public void checkServerTrusted(
                    java.security.cert.X509Certificate[] x509Certificates,
                    String s) throws java.security.cert.CertificateException {
            }
    
            @Override
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return new java.security.cert.X509Certificate[] {};
            }
        } };
        try {
            SSLContext sc = SSLContext.getInstance("TLS");
            sc.init(null, trustAllCerts, new java.security.SecureRandom());
            client.setSslSocketFactory(sc.getSocketFactory());
        } catch (Exception e) {
            e.printStackTrace();
        }
    
    
             clent.protocols(Collections.singletonList(Protocol.HTTP_1_1))
             .build();

    WebView访问https页面

    服务器证书校验主要针对 WebView 的安全问题。
    在 app 中需要通过 WebView 访问 url,因为服务器采用的自签名证书,而不是 ca 认证,使用 WebView 加载 url 的时候会显示为空白,出现无法加载网页的情况。
    使用 ca 认证的证书,在 WebView 则可以直接显示出来,不需要特殊处理。
    以往针对自签名证书的解决方案是继承 WebViewClient 重写 onReceivedSslError 方法,然后直接使用 handler.proceed(),该方案其实是忽略了证书,存在安全隐患。
    安全的方案是当出现了证书问题的时候,读取 asserts 中保存的的根证书,然后与服务器校验,假如通过了,继续执行 handler.proceed(),否则执行 handler.cancel()。

    简单的解决方案(不安全)

    wv.setWebViewClient(new WebViewClient(){
    
    @override
    public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error){
    
    //handler.cancel(); 默认的处理方式,WebView变成空白页
      handler.proceed();接受证书
    
    //handleMessage(Message msg); 其他处理
    }
    
    // 这行代码一定加上否则效果不会出现  
     webView.getSettings().setJavaScriptEnabled(true);  

    直接运行是页面是可以打开的。但是打好签名包之后,依旧打不开!
    一路追踪之后,发现是那个方法被混淆了
    proguard:mapping.txt
    xx.xx.xxx
        xx.xx.xxx this$0 -> a
        void onReceivedSslError(android.webkit.WebView,android.webkit.SslErrorHandler,android.net.http.SslError) -> onReceivedSslError

    所以还要必要在混淆文件proguard.cfg中,加入以下:
    -keep public class android.net.http.SslError

    -dontwarn android.webkit.WebView
    -dontwarn android.net.http.SslError
    -dontwarn Android.webkit.WebViewClient

    还有一点要提到的是,如果手机添加了代理。也是打不开的。此时,需要将代理的证书导入到Android设备。以Fiddler为例:

    Fiddler本质上是一个HTTPS代理服务器,其自己带的证书显然不会在Android设备的受信任证书列表里。

    有些应用程序会查看服务器端的证书是否是由受信任的根证书签名的,如果不是就直接跳出。

    所以,为了保险起见,我们要将Fiddler代理服务器的证书导到Android设备上。

    导入的过程非常简单,打开设备自带的浏览器,在地址栏中输入代理服务器的IP和端口,例如本例中我们会输入192.169.11.8:8888,进入之后会看到一个Fiddler提供的页面。点击页面中的“FiddlerRoot certificate”链接,接着系统会弹出对话框。输入一个证书名称,然后直接点“确定”就好了。

    但是,如果网页中含有图片,而图片采用的协议是http,那么图片将无法显示。这是因为,

    Android webview 从Lollipop(5.0)开始webview默认不允许混合模式,https当中不能加载http资源,需要设置开启。

    Mixed content using HTTP and HTTPS on WebViews are disabled by default starting Lollipop. Is possible that is not working on devices with Lollipop? If this is the case, you can change the default WebView setting on Lollipop using:

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        settings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
    }

    安全的解决方案

    public class WebviewClient3 extends WebViewClient {
        private Context context;
    
        public WebviewClient3(Context context) {
            this.context = context;
        }
    
        @Override
        public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
            test12306(handler, view.getUrl());
        }
    
        // 以 12306 的证书为例,因为 12306 的证书是自签名的
        private void test12306(final SslErrorHandler handler, String url) {
            OkHttpClient.Builder builder;
            try {
                builder = setCertificates(new OkHttpClient.Builder(), context.getAssets().open(MainActivity.cer_protal_root));
            } catch (IOException e) {
                builder = new OkHttpClient.Builder();
            }
            Request request = new Request.Builder().url(url)
                    .build();
            builder.build().newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    Log.e("12306 error", e.getMessage());
                    handler.cancel();
                }
    
                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    Log.e("12306 ", response.body().string());
                    handler.proceed();
                }
            });
        }
    
        private OkHttpClient.Builder setCertificates(OkHttpClient.Builder client, InputStream... certificates) {
            try {
                CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
                KeyStore keyStore = KeyStore.getInstance("PKCS12", "BC");
                keyStore.load(null);
                int index = 0;
                for (InputStream certificate : certificates) {
                    String certificateAlias = Integer.toString(index++);
                    keyStore.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(certificate));
    
                    try {
                        if (certificate != null)
                            certificate.close();
                    } catch (IOException e) {
                    }
                }
                SSLContext sslContext = SSLContext.getInstance("TLS");
                TrustManagerFactory trustManagerFactory =
                        TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
                trustManagerFactory.init(keyStore);
                sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());
                SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
                X509TrustManager trustManager = Platform.get().trustManager(sslSocketFactory);
                client.sslSocketFactory(sslSocketFactory, trustManager);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return client;
        }
    }

    以上代码可以针对规范的自签名证书进行校验了。但是呢,我们的证书不规范,会出现 Hostname xxx not verified 的情况。这种情况需要对 Hostname 进行校验。需要在 client 上添加如下代码:

    client.hostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                String peerHost = session.getPeerHost();//服务器返回的域名
                try {
                    X509Certificate[] peerCertificates = (X509Certificate[]) session.getPeerCertificates();
                    for (X509Certificate c : peerCertificates) {
                        X500Principal subjectX500Principal = c.getSubjectX500Principal();
                        String name = new X500p(subjectX500Principal).getName();
                        String[] split = name.split(",");
                        for (String s : split) {
                            if (s.startsWith("CN")) {
                                if (s.contains(hostname) && s.contains(peerHost)) {
                                    return true;
                                }
                            }
                        }
                    }
                } catch (SSLPeerUnverifiedException e) {
                    e.printStackTrace();
                }
                return false;
            }
        });


    展开全文
  • 今天小编就为大家分享一篇快速解决android webview https图片不显示的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
  • webview请求https

    2017-01-10 11:10:39
    1:集成WebViewClient 复写 @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { if (!isNewPager) { view.loadUrl(url); return !isNewPager; } else

    1:集成WebViewClient
    复写

    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        if (!isNewPager) {
            view.loadUrl(url);
            return !isNewPager;
        } else
            return isNewPager;
    }
    
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
        return shouldOverrideUrlLoading(view, request.getUrl().getPath());
    }
    
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    @Override
    public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
        return this.shouldInterceptRequest(view, request.getUrl().getPath());
    }
    
    @Override
    public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
        try {
            HttpURLConnection urlConnection = createConnection(url, "");
            InputStream is = urlConnection.getInputStream();
            String contentType = urlConnection.getContentType();
            String encoding = urlConnection.getContentEncoding();
            if (contentType != null) {
                String mimeType = contentType;
                if (contentType.contains(";")) {
                    mimeType = contentType.split(";")[0].trim();
                }
                return new WebResourceResponse(mimeType, encoding, is);
            }
    
        } catch (Exception e) {
            e.printStackTrace();
        }
        return super.shouldInterceptRequest(view, url);
    }

    2:创建网络请求

    @Override
    public HttpURLConnection createConnection(String url, Object extra) throws IOException {
        HttpURLConnection connection = createConnection(url, extra);
        if (connection instanceof HttpsURLConnection) {
            if (sslContext == null)
                try {
                    sslContext = getSSLContext(OkHttpUtil.LCE);//证书地址
                } catch (Exception e) {
                    e.printStackTrace();
                }
            if (sslContext == null)
                try {
                    sslContext = getSSLContext();//不验证证书
                } catch (Exception e) {
                    e.printStackTrace();
                }
            if (sslContext != null) {
                ((HttpsURLConnection) connection).setSSLSocketFactory(sslContext.getSocketFactory());
                ((HttpsURLConnection) connection).setHostnameVerifier((new HostnameVerifier() {
                    @Override
                    public boolean verify(String s, SSLSession sslSession) {
                        return true;
                    }
                }));
            }
        }
        return connection;
    }
    protected HttpURLConnection createConnection(String url, Object extra) throws IOException {
        String encodedUrl = Uri.encode(url, "@#&=*+-_.,:!?()/~\'%");
        HttpURLConnection conn = (HttpURLConnection)(new URL(encodedUrl)).openConnection();
        conn.setConnectTimeout(this.connectTimeout);
        conn.setReadTimeout(this.readTimeout);
        return conn;
    }


    3:获取sll证书

    public static SSLContext getSSLContext(String trustStorePath) throws Exception {
        // 实例化信任库
        TrustManagerFactory trustManagerFactory = TrustManagerFactory
                .getInstance(TrustManagerFactory.getDefaultAlgorithm());
        // 获得信任库
        KeyStore trustStore = getKeyStore(trustStorePath);//证书位置
        // 初始化信任库
        trustManagerFactory.init(trustStore);
        // 实例化SSL上下文
        SSLContext ctx = SSLContext.getInstance("TLS");
        // 初始化SSL上下文
        ctx.init(null,
                trustManagerFactory.getTrustManagers(), new SecureRandom());
        // 获得SSLSocketFactory
        return ctx;
    }
    
    
    private static final KeyStore getKeyStore(String c) throws CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException {
        InputStream is = context.getAssets().open(c);
        CertificateFactory cerFactory = CertificateFactory.getInstance("X.509");
        Certificate cer = cerFactory.generateCertificate(is);
        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        keyStore.load(null, null);
        keyStore.setCertificateEntry(c, cer);
        if (is != null)
            is.close();
        return keyStore;
    }
    
    public static final SSLContext getSSLContext() throws Exception {
        TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
            @Override
            public void checkClientTrusted(java.security.cert.X509Certificate[] x509Certificates, String s) throws CertificateException {
    
            }
    
            @Override
            public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String s) throws CertificateException {
    
            }
    
            @Override
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return new java.security.cert.X509Certificate[0];
            }
        }};
    
        SSLContext sc = SSLContext.getInstance("TLS");
        sc.init(null, trustAllCerts, new java.security.SecureRandom());
        return sc;
    }
     

    4:给webView设置WebViewClient       就ok
    展开全文
  • 主要介绍了android教程使用webview访问https的url处理sslerror示例,大家参考使用吧
  • Android通过WEBVIEW调用HTTPS
  • 今天小编就为大家分享一篇Android 7.0系统webview 显示https页面空白处理方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
  • android 用webview加载网页(https和http)

    万次阅读 2017-01-06 18:42:54
    当load有ssl层的https页面时,如果这个网站的安全证书在Android无法得到认证,WebView就会变成一个空白页,而并不会像PC浏览器中那样跳出一个风险提示框。因此,我们必须针对这种情况进行处理。(这个证书限于2.1版本...

    1.Android 加载https请求的网页的时候 打不开

         当load有ssl层的https页面时,如果这个网站的安全证书在Android无法得到认证,WebView就会变成一个空白页,而并不会像PC浏览器中那样跳出一个风险提示框。因此,我们必须针对这种情况进行处理。(这个证书限于2.1版本以上的Android 系统才可以)

         

    wv.setWebViewClient(new WebViewClient(){
    
    @override
    public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error){
    
    //handler.cancel(); 默认的处理方式,WebView变成空白页
      handler.process();接受证书
    
    //handleMessage(Message msg); 其他处理
    }
    
    // 这行代码一定加上否则效果不会出现  
     webView.getSettings().setJavaScriptEnabled(true);  
    
    
    查看Android浏览器源码在TabControl.Java类中SubWindowClient方法中找,如果只是简单的接受所有证书的话,就直接调process()方法就行了
    写到这里之后,直接运行是页面是可以打开的。但是打好签名包之后,依旧打不开!!!
    一路追踪之后,发现是那个方法被混淆了
    proguard:mapping.txt
    xx.xx.xxx
         xx.xx.xxx this$0 -> a
        void onReceivedSslError(android.webkit.WebView,android.webkit.SslErrorHandler,android.net.http.SslError) -> onReceivedSslError

    所以还要必要在混淆文件proguard.cfg中,加入以下:
    -keep public class android.net.http.SslError

    -dontwarn android.webkit.WebView
    -dontwarn android.net.http.SslError

    -dontwarn Android.webkit.WebViewClient


    还有一点要提到的是,如果手机添加了代理。也是打不开的

     

    但是sslerror是从2.2才开始提供的。之前的版本怎么办?
    可以把android2.2中onReceivedSslError()的源码导入到自己的工程中,具体方法如下:
    先把android2.2包中的SslError.java和WebViewClient.java导入到自己的工程中,在导入时需要建立和android2.2源码包中一样的包名。然后在用webview的时候导包就导自己工程里的这个包名就行!

    注意一下 webView 要设置的几个地方兴许能帮上忙:
    1 . 默认情况下,不能访问 https,需要重写 WebViewClient 的 onReceivedSslError
    ps: API Level > 2.1,或者提供 SslError.java 和 WebViewClient.java 文件
    重写部分一般可以不做特殊处理,直接 handler.process(); 接受证书即可

    2 . 默认情况下,不能弹 js 框,需要重写 WebChromeClient 的 onJsAlert
    重写部分也不需要特殊处理,直接返回 super.onJsAlert(view, url, message, result);

    pps: 要 setWebViewClient 和 setWebChromeClient,webView 才能生效


    2.Android 用webview加载网页 可能会出现另外一种情况:

         webview加载的网页是http请求的 ,如果网页里有一张图片,并且该图片的地址是https请求的,这时候用webview加载网页,图片是不显示的。

        会报这种错

          

     Mixed Content as loaded over HTTPS, but requested an insecure image 

    意思是  http请求和https请求混淆了

    注意: 用webview加载网页,一定用同一种请求

    展开全文
  • 在Android5.0及以上系统,当WebView加载的链接为https开头,但是链接里面的内容,比如图片为http链接,这时候,图片就不能正常加载(加载不出来)。 由于自己在项目中踩坑遇到此问题,也是各种查阅尝试,最终得以...

    Android5.0及以上系统,当WebView加载的链接为https开头,但是链接里面的内容,比如图片为http链接,这时候,图片就不能正常加载(加载不出来)。

    由于自己在项目中踩坑遇到此问题,也是各种查阅尝试,最终得以解决,特此记录下:

     在Android5.0中,WebView方面做了些修改,如果你的系统target api为21以上:

    • 系统默认禁止了mixed content和第三方cookie。可以使用setMixedContentMode() 和 setAcceptThirdPartyCookies()以分别启用。
    • 系统现在可以智能选择HTML文档的portion来绘制。这种新特性可以减少内存footprint并改进性能。若要一次性渲染整个HTML文档,可以调用这个方法enableSlowWholeDocumentDraw()
    • 如果你的app的target api低于21:系统允许mixed content和第三方cookie,并且总是一次性渲染整个HTML文档。

    一、WebView链接为https,内容图片为http,图片不能正常显示,原因主要是:

           webview 从Lollipop(5.0)开始 webview默认不允许混合模式,https当中不能加载http资源,如果要加载,需单独设置开启,

    二、解决方案:

    1.在加载钱先阻塞图片加载:
    
    setting.setBlockNetworkImage(true);
    
    (在webview加载页面之前,设置加载模式为MIXED_CONTENT_ALWAYS_ALLOW)
    // 允许从任何来源加载内容,即使起源是不安全的
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        webView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
    }
    2.在WebView 渲染完成后,解除阻塞,加载图片 
    webView.setWebViewClient(new WebViewClient() {
                    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
                    @Override
                    public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
                        String  s = request.getUrl().toString();
                        view.loadUrl(s);
                        return true;
                    }
    
                    @Override
                    public void onPageFinished(WebView view, String url) {
                        progressBar.setVisibility(View.GONE);
                        Log.i(TAG, "onPageFinished-->" + url);
    
                        settings.setBlockNetworkImage(false);//解除阻塞
                        //判断webview是否加载了,图片资源
                        if (!settings.getLoadsImagesAutomatically()) {
                            settings.setLoadsImagesAutomatically(true); //设置wenView加载图片资源
                        }
    
                        super.onPageFinished(view, url);
                    }
    
                });
            }

     更多参考链接:Android官网解释链接 

    三、相关问题拓展

    WebView中加载页面错误,自定义view 处理加载失败页面

    展开全文
  • 1、WebView HTTPS与HTTP混合使用出现的错误 Mixed Content: The page at 'xxx' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'xxxxxxxxx'. This request has been blocked; the ...
  • 前阵子为了发布新版本APP,没有时间去解决Android 中webView无法加载https协议,由于能加载http协议就没有去深究原因,今天要发布新版本,还有足够的时间,就查了一下这个问题。 Google了一下,查到了一些方法,在这...
  • 解决Webview加载不了https请求中的http图片 //允许混合内容 解决部分手机 加载不出https请求里面的http下的图片 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { settings.setMixedContentMode...
  • WebView2示例 该存储库包含入门应用程序以及演示功能和使用模式的示例应用程序。 当我们向WebView2添加更多功能时,我们将定期更新示例。 在GettingStarted文件夹... 通过运行git clone https://github.com/MicrosoftE
  • 最近做无线WiFi的时候,在最后认证成功的时候会弹出一个广告页,于是用webview去加载了一下,结果没反应,打印url出来看了一下,发现是https格式的,在使用WebView加载https资源文件时,如果认证证书不被Android认可...
  • webView.setWebViewClient(new WebViewClient() { @Override public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { // T
  • WebView 加载https 白屏以及重定向加载

    千次阅读 2018-03-06 18:29:47
    前言:今天在处理app 内广告跳转的问题时候,遇到官网 公司官网 https 点击打不开的情况,因为公司官网在手机页面上会重定向到手机版的页面去,处理到最后发现是一个细节导致的,特地记录下解决过程。1.针对正常的...
  • (2)cordova plugin add https://github.com/runner525/x5webview-cordova-plugin.git 二.熟悉android开发的同学可以参考x5官网来灵活使用x5内核.常用链接如下: 官网() 常见问题() 论坛() 内核加载问题检测工具()
  • 解决webview加载https链接的问题,重点是需要验证.cer格式的证书。公司是做理财项目的所以为了安全考虑做了一个CA颁发的证书就是上面说的.cer格式的证书,希望对有需要的人有帮助。
  • webView加载Https网页

    2017-11-18 10:18:46
    方式一 //android 版本 5.0之后加载https空白页:由于android5.0版本之前默认允许加载混合网络协议内容;5.0之后默认不允许,设置webView允许加载混合网络协议即可
  • 有些时候由于Android系统的bug或者其他的原因,导致我们的webview不能验证通过我们的https证书,最明显的例子就是华为手机mate7升级到Android7.0后,手机有些网站打不开了,而更新了webview的补丁后就没问题了
  • android Webview 打开https链接

    万次阅读 2019-06-11 20:24:08
    参考这篇 解决了 打开 https链接... 详细的Webview使用攻略 package com.mycompany.myapp2; import android.content.Context; import android.app.*; import android.os.*; import android.util.*; import andr...
  • android 让webview支持https 双向认证(SSL)

    万次阅读 热门讨论 2013-07-03 15:15:20
    所以涉及到https双向认证,在网上找了很多资料都没有完美的解决方案。最后参考了org.sandrob.sslexample的实现方式,结合实际情况才完成该技术难题,现在分享一下我的实现方案来弥补这方面的空白。 正文: 1....
  • https://github.com/fangkyi03/wechat-webview-template 项目介绍 1.wechat 使用taro创建的初始化项目 2.react-ssr-h5 使用nextjs创建的项目 已经做好完整的兼容处理 使用vw vh为单位 简单介绍 因小程序对于...
  • QT通过URL(网址)使用WebView访问指定网页,完整代码,可直接运行。也可修改main.cpp中注释掉的代码,通过接收参数来访问指定网页

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 46,999
精华内容 18,799
关键字:

httpswebview