1. 程式人生 > >Fresco 在Android 4.4 版本 載入https圖片問題 javax.net.ssl.SSLHandshakeException

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

TLSv1.1和TLSv1.2從Android4.1(Api級別16)開始才被支援,從Android4.4 Wear(Api級別20)才被啟用(手機是Android5.0,Api級別21) AS中SDK Platforms預覽 截了一張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 在這裡插入圖片描述 既然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;

    }
}