有没有办法在旧设备上的Picasso库中启用TLS 1.2?
我的应用程序正在使用来自HTTPS源的图像,Solar Dynamics Observatory,并且这些图像加载在API版本的API版本(5.0)(我认为API 20可以工作)或更高的版本上很好,但我无法加载这些到API 19的Android版本从API 16(分钟API,我为我的应用程序设置)图像这里是一个的加载图像的代码,这是很基本的 -有没有办法在旧设备上的Picasso库中启用TLS 1.2?
Picasso.with(this)
.load("https://sdo.gsfc.nasa.gov/assets/img/latest/latest_2048_HMIIC.jpg")
.placeholder(R.drawable.placeholdernew)
.error(R.drawable.errornew)
.into(mImageView, new com.squareup.picasso.Callback() {
@Override
public void onSuccess() {
mAttacher = new PhotoViewAttacher(mImageView); //this adds the zoom function after the picture is loaded successfully, so the user couldn't zoom the placeholder or error picture :)
}
@Override
public void onError() {
Log.d("Pic Error", "Loading Error");
}
});
正如你所看到的,有没有错误在我的代码中(我认为:P)。我使用SSLLabs站点检查了SDO站点,并且此站点表示此SDO服务器不接受比API 20旧的Android设备上的TLS握手。是否有任何方法在旧版Android版本中启用Picasso中的TLS 1.2?帮助将不胜感激!在此先感谢:)
嗯,这工作,但它是丑陋的。
在你的项目的依赖,增加:
compile 'com.squareup.picasso:picasso:2.5.2'
compile 'com.squareup.okhttp3:okhttp:3.6.0'
compile 'com.jakewharton.picasso:picasso2-okhttp3-downloader:1.0.2'
(你可能已经安装了picasso
线—我只是确保你使用的是最新版本)
接下来,这个类添加到你的项目(基于this answer):
public static class TLSSocketFactory extends SSLSocketFactory {
private SSLSocketFactory internalSSLSocketFactory;
public TLSSocketFactory(SSLSocketFactory delegate) throws
KeyManagementException, NoSuchAlgorithmException {
internalSSLSocketFactory = delegate;
}
@Override
public String[] getDefaultCipherSuites() {
return internalSSLSocketFactory.getDefaultCipherSuites();
}
@Override
public String[] getSupportedCipherSuites() {
return internalSSLSocketFactory.getSupportedCipherSuites();
}
@Override
public Socket createSocket(Socket s, String host, int port, boolean autoClose)
throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(s, host, port, autoClose));
}
@Override
public Socket createSocket(String host, int port) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port));
}
@Override
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port, localHost, localPort));
}
@Override
public Socket createSocket(InetAddress host, int port) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port));
}
@Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(address, port, localAddress, localPort));
}
/*
* Utility methods
*/
private static Socket enableTLSOnSocket(Socket socket) {
if (socket != null && (socket instanceof SSLSocket)
&& isTLSServerEnabled((SSLSocket) socket)) { // skip the fix if server doesn't provide there TLS version
((SSLSocket) socket).setEnabledProtocols(new String[]{"TLSv1.1", "TLSv1.2"});
}
return socket;
}
private static boolean isTLSServerEnabled(SSLSocket sslSocket) {
System.out.println("__prova__ :: " + sslSocket.getSupportedProtocols().toString());
for (String protocol : sslSocket.getSupportedProtocols()) {
if (protocol.equals("TLSv1.1") || protocol.equals("TLSv1.2")) {
return true;
}
}
return false;
}
}
(即类是public static
,所以是德西限制标准在里面别的东西—刚刚摆脱static
的嵌套类,如果你希望它是一个独立的类)
然后,在你的类,它是用毕加索,添加此方法的基础上,this issue comment:
public X509TrustManager provideX509TrustManager() {
try {
TrustManagerFactory factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
factory.init((KeyStore) null);
TrustManager[] trustManagers = factory.getTrustManagers();
return (X509TrustManager) trustManagers[0];
}
catch (NoSuchAlgorithmException exception) {
Log.e(getClass().getSimpleName(), "not trust manager available", exception);
}
catch (KeyStoreException exception) {
Log.e(getClass().getSimpleName(), "not trust manager available", exception);
}
return null;
}
最后,此代码应成功下载你的形象:
SSLContext sslContext=SSLContext.getInstance("TLS");
sslContext.init(null, null, null);
SSLSocketFactory noSSLv3Factory;
if (Build.VERSION.SDK_INT<=Build.VERSION_CODES.KITKAT) {
noSSLv3Factory=new TLSSocketFactory(sslContext.getSocketFactory());
}
else {
noSSLv3Factory=sslContext.getSocketFactory();
}
OkHttpClient.Builder okb=new OkHttpClient.Builder()
.sslSocketFactory(noSSLv3Factory, provideX509TrustManager());
OkHttpClient ok=okb.build();
Picasso p=new Picasso.Builder(getActivity())
.downloader(new OkHttp3Downloader(ok))
.build();
p.load(
"https://sdo.gsfc.nasa.gov/assets/img/latest/latest_2048_HMIIC.jpg")
.fit().centerCrop()
.placeholder(R.drawable.owner_placeholder)
.error(R.drawable.owner_error).into(icon);
(在这里您将与是正确的为您的项目代替我fit()
和后续调用)
如果你碰巧知道维护NASA服务器的人......他们真的应该升级他们的SSL支持。只是在说'。
哇,非常感谢!我明天会测试它,并让你知道它是否正常工作:) – Hamstersztyk
再次感谢你,图像加载实际上是在旧设备上工作! :) – Hamstersztyk
如果您添加OkHttp,您可以尝试配置OkHttp以支持TLS 1.2,如[其中一些答案](http://stackoverflow.com/q/28943660/115145)中所述,然后让毕加索使用您的'OkHttpClient '。我会在下周初尝试编写一些代码。非常感谢包含一个真实的URL,因为这将有助于测试。 – CommonsWare
谢谢你。如果你想测试图像,只需点击任何太阳图像(如果它在我的应用程序中使用2048图像和512图像)。我正在等待代码:) – Hamstersztyk