有没有办法在旧设备的Picasso库中启用TLS 1.2? [英] Is there a way to enable TLS 1.2 in Picasso library on older devices?

查看:59
本文介绍了有没有办法在旧设备的Picasso库中启用TLS 1.2?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的应用正在使用HTTPS来源 Solar Dynamics天文台,并且这些图片在具有API 21(5.0)的Android版本(我认为API 20也可以正常工作)或更高版本上加载得很好,但我无法从API 16(最低要求)加载这些图片.我为我的应用程序设置的API)是API19.这是加载图像的代码,非常基本-

My app is using images from HTTPS source, Solar Dynamics Observatory, and these images are loading just fine on Android versions with API 21 (5.0) (I think that API 20 would work as well) or higher, but I can't load these images on Android versions from API 16 (min. API that I set for my app) to API 19. Here's the code that's loading the images, it's pretty basic -

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?帮助将不胜感激!在此先感谢:)

As you can see, there are no errors in my code (I think :P). I checked the SDO site with SSLLabs site, and this site said that this SDO server is not accepting TLS handshake on Android devices older than API 20. Is there any way to enable TLS 1.2 in Picasso on older Android versions? Help would be appreciated! Thanks in advance :)

推荐答案

嗯,这行得通,但是很丑.

Well, this works, but it's ugly.

在项目的依赖项中,添加:

In your project's dependencies, add:

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行—我只是确保您使用的是最新版本)

(you may already have the picasso line — I am just making sure that you are on the latest version)

接下来,将此类添加到您的项目中(基于此答案):

Next, add this class to your project (based on 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即可)

(that class is public static, and so is designed to be a nested class inside something else — just get rid of the static if you want it to be a standalone class)

然后,在使用Picasso的类中,根据这个问题的评论:

Then, in your class that is using Picasso, add this method, based on 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;
  }

最后,此代码应成功下载您的图片:

Finally, this code should successfully download your image:

    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()和后续调用替换我的fit()和后续调用)

(where you would replace my fit() and subsequent calls with the right ones for your project)

如果您碰巧知道维护该NASA服务器的人员...他们真的应该升级其SSL支持.只是说'.

If you happen to know the people maintaining that NASA server... they really ought to upgrade their SSL support. Just sayin'.

这篇关于有没有办法在旧设备的Picasso库中启用TLS 1.2?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆