Fresco 在Android 4.4 版本 加载https图片问题 javax.net.ssl.SSLHandshakeException

由于Android系统的不同版本支持的TLS 版本不同,导致Fresco 加载https图片(图片来源于不同服务器,并且配置不一样)出现SSLHandshakeException
TLS 用于在两个通信应用程序之间提供保密性和数据完整性。TLS 1.0可以理解成SSL3.0 的升级版SSL3.1,TLS已有1.0,1.1,1.2,1.3版本。HTTPS与HTTP区别 – TLS/SSL

不同版本的TLS在Android中的支持情况参考Google SSLEngine(需要VPN)

TLSv1.1和TLSv1.2从Android4.1(Api级别16)开始才被支持,从Android4.4 Wear(Api级别20)才被启用(手机是Android5.0,Api级别21)
Fresco 在Android 4.4 版本 加载https图片问题 javax.net.ssl.SSLHandshakeException_第1张图片
截了一张AS中的SDK图片
下面是Fresco加载图片出现的2个错误

Caused by: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x6ce85028: 
Failure in SSL library, usually a protocol error
System.err: error:1407742E:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version 
SSL handshake aborted: ssl=0x6d1da010: Failure in SSL library, usually a protocol error
W/System.err: error:14077102:SSL routines:SSL23_GET_SERVER_HELLO:
unsupported protocol (external/openssl/ssl/s23_clnt.c:714 0x63608894:0x00000000)

第一个错误 是图片来源的服务器配置了TLS1.2
第二个错误 是图片来源的服务器配置了TLS1.0

如何查看资源来源TLS版本?打开Google浏览器,按F12,查看Security
Fresco 在Android 4.4 版本 加载https图片问题 javax.net.ssl.SSLHandshakeException_第2张图片
既然4.4版本TLS未启用,所以配置SSLSocketFactory启用TLS,
Fresco 可以选择OKHttp库加载图片,然后构建OKHttp的SSLSocketFactory
Gradle 配置:

compile 'com.facebook.fresco:fresco:1.10.0'
compile 'com.facebook.fresco:imagepipeline-okhttp3:1.10.0'

在Application的onCreate()中配置如下:

 /**
     * Fresco 配置
     */
    private void FrescoInit() {
        OkHttpClient okHttpClient= getUnsafeOkHttpClient();  // build on your own
        ImagePipelineConfig config = OkHttpImagePipelineConfigFactory
                .newBuilder(this, okHttpClient)
                .build();
        Fresco.initialize(this, config);

    }
  private class  TrustAllManager implements X509TrustManager{

        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {

        }

        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {

        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[0];
//            return new java.security.cert.X509Certificate[]{};
        }
    }
  /**
     * 配置OKhttp
     * @return
     */
    public OkHttpClient getUnsafeOkHttpClient() {
        try {
            // Create a trust manager that does not validate certificate chains
            // Install the all-trusting trust manager
            final SSLContext sslContext = SSLContext.getInstance("TLS");
            x509TrustManager = new TrustAllManager();
            sslContext.init(null, new TrustManager[] { x509TrustManager }, 
            new java.security.SecureRandom());
            // Create an ssl socket factory with our all-trusting manager
         /*   final SSLSocketFactory sslSocketFactory = sslContext
                    .getSocketFactory();*/
            final SSLSocketFactory sslSocketFactory = new Tls12SocketFactory(sslContext
                    .getSocketFactory());

            OkHttpClient okHttpClient = new OkHttpClient()
                    .newBuilder()
                    .sslSocketFactory(sslSocketFactory,x509TrustManager)
                    .hostnameVerifier(new HostnameVerifier() {
                        @Override
                        public boolean verify(String hostname, SSLSession session) {
                            return true;
                        }
                    })
                    .build();
            return okHttpClient;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

Tls12SocketFactory 类extends SSLSocketFactory

public class Tls12SocketFactory extends SSLSocketFactory {
    private static final String[] TLS_SUPPORT_VERSION = {"TLSv1","TLSv1.1", "TLSv1.2"};

    final SSLSocketFactory delegate;

    public Tls12SocketFactory(SSLSocketFactory delegate) {
        this.delegate = delegate;
    }

    @Override
    public String[] getDefaultCipherSuites() {
        return delegate.getDefaultCipherSuites();
    }

    @Override
    public String[] getSupportedCipherSuites() {
        return delegate.getSupportedCipherSuites();
    }

    @Override
    public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
        return patch(delegate.createSocket(s, host, port, autoClose));
    }

    @Override
    public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
        return patch(delegate.createSocket(host, port));
    }

    @Override
    public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
        return patch(delegate.createSocket(host, port, localHost, localPort));
    }

    @Override
    public Socket createSocket(InetAddress host, int port) throws IOException {
        return patch(delegate.createSocket(host, port));
    }

    @Override
    public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
        return patch(delegate.createSocket(address, port, localAddress, localPort));
    }

    private Socket patch(Socket s) {
        if (s instanceof SSLSocket) {
            ((SSLSocket) s).setEnabledProtocols(TLS_SUPPORT_VERSION);
        }
        return s;

    }
}

参考:
Android HTTPS、TLS版本支持相关解决方案
OkHttpUtils: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0xb8f02e68
不同版本的TLS在Android中的支持情况
https://stackoverflow.com/questions/29916962/javax-net-ssl-sslhandshakeexception-javax-net-ssl-sslprotocolexception-ssl-han
当Fresco/Picasso遇到https(1)----https跳过证书验证
Android 设置客户端支持的TLS支持的版本号

你可能感兴趣的:(Fresco)