Fresco 在Android 4.4 版本 載入https圖片問題 javax.net.ssl.SSLHandshakeException
阿新 • • 發佈:2018-12-15
由於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圖片 下面是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;
}
}