Picasso加载https的图片加载不出来的解决方案

  • 最近项目中有需求–要显示https链接的图片,但是配置好路径后原生的Picasso死活没法加载出图片,最后在网上找到了如下的解决办法
  • 确认依赖
  • compile 'com.squareup.okhttp3:okhttp:3.9.0'
  • compile 'com.squareup.picasso:picasso:2.5.2'
  1. 自定义类 ImageDownLoader 实现 com.squareup.picasso.Downloader 代码如下:
package china.test.helper;
    import android.net.Uri;             
    import com.squareup.picasso.Downloader;
    import com.squareup.picasso.NetworkPolicy;  
    import java.io.IOException;             
    import okhttp3.Cache;
    import okhttp3.CacheControl;
    import okhttp3.OkHttpClient;
    import okhttp3.ResponseBody;
    import okhttp3.Request;


    /**
     * Created by benchengzhou on 2017/11/14  13:52 .
     * 作者邮箱: mappstore@163.com
     * 功能描述: 重写picasso的下载器,修改使用okhttp3作为下载
     * 类    名: ImageDownLoader
     * 备    注:
     */

    public class ImageDownLoader implements Downloader {
       /* OkHttpClient client = new OkHttpClient.Builder()
                .protocols(Collections.singletonList(Protocol.HTTP_1_1))
                .build();*/
        private OkHttpClient  client= null;

        public ImageDownLoader(OkHttpClient okHttpClient) {
            this.client = okHttpClient;
        }

        @Override
        public Response load(Uri uri, int networkPolicy) throws IOException {
            CacheControl cacheControl = null;
            if (networkPolicy != 0) {
                if (NetworkPolicy.isOfflineOnly(networkPolicy)) {
                    cacheControl = CacheControl.FORCE_CACHE;
                } else {
                    CacheControl.Builder builder = new CacheControl.Builder();
                    if (!NetworkPolicy.shouldReadFromDiskCache(networkPolicy)) {
                        builder.noCache();
                    }
                    if (!NetworkPolicy.shouldWriteToDiskCache(networkPolicy)) {
                        builder.noStore();
                    }
                    cacheControl = builder.build();
                }
            }

            Request.Builder builder = new Request.Builder().url(uri.toString());
            if (cacheControl != null) {
                builder.cacheControl(cacheControl);
            }

            okhttp3.Response response = client.newCall(builder.build()).execute();
            int responseCode = response.code();
            if (responseCode >= 300) {
                response.body().close();
                throw new ResponseException(responseCode + " " + response.message(), networkPolicy,
                        responseCode);
            }

            boolean fromCache = response.cacheResponse() != null;

            ResponseBody responseBody = response.body();
            return new Response(responseBody.byteStream(), fromCache, responseBody.contentLength());


        }




        @Override
        public void shutdown() {

            Cache cache = client.cache();
            if (cache != null) {
                try {
                    cache.close();
                } catch (IOException ignored) {
                }
            }
        }
    }
  • 2.解决 Picasso 初始化配置使用我们自定义的 Downloader ,在application中添加初始化配置代码
/**
 *  初始化picasso使用okhttp作为网络请求框架
 */
private void initPicasso() {

    Picasso.setSingletonInstance(new Picasso.Builder(this).
    downloader(new ImageDownLoader(getSOkHttpClient())).loggingEnabled(true)
    .build());

}
  • 3.getSOkHttpClient() 中的代码
/**
 * 创建全局OkHttpClient对象
 * <p>
 * OkHttpClient 用于管理所有的请求,内部支持并发,
 * 所以我们不必每次请求都创建一个 OkHttpClient 对象,这是非常耗费资源的。接下来就是创建一个 Request 对象了
 *
 * @return
 */
public static OkHttpClient getSOkHttpClient() {
    //创建okhttp的请求对象 参考地址  http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0106/2275.html

    if (sOkHttpClient == null) {
        sOkHttpClient =
                new OkHttpClient.Builder()
                        .readTimeout(20000, TimeUnit.SECONDS)//设置读取超时时间
                        .writeTimeout(20000, TimeUnit.SECONDS)//设置写的超时时间
                        .connectTimeout(20000, TimeUnit.SECONDS)//设置连接超时时间
                        .sslSocketFactory(createSSLSocketFactory())    //添加信任所有证书
                        .hostnameVerifier(new HostnameVerifier() {     //信任规则全部信任
                            @Override
                            public boolean verify(String hostname, SSLSession session) {
                                return true;
                            }
                        })
                        .build();
    }
    return sOkHttpClient;
}
  • 3.1这里的 OkHttpClient 对象全局使用一个,同时可以作为项目的okhttp的网络请求的OkHttpClient的封装,我的项目里面的网络请求也是使用的这一个
  • 其中
.sslSocketFactory(createSSLSocketFactory())    //添加信任所有证书
                            .hostnameVerifier(new HostnameVerifier() {     //信任规则全部信任
                                @Override
                                public boolean verify(String hostname, SSLSession session) {
                                    return true;
                                }
                            })
  • 是增加的对https协议的支持
  • 4.createSSLSocketFactory 方法中增加 信任规则
/**
     * 测试环境https添加全部信任
     * okhttp的配置
     *
     * @return
     */
    private static SSLSocketFactory createSSLSocketFactory() {
        SSLSocketFactory ssfFactory = null;

        try {
            SSLContext sc = SSLContext.getInstance("TLS");
            sc.init(null, new TrustManager[]{new TrustAllCerts()}, new SecureRandom());

            ssfFactory = sc.getSocketFactory();
        } catch (Exception e) {
        }

        return ssfFactory;
    }
  • 5.创建一个行的文件 TrustAllCerts.java 配置对应的信任规则
package china.test.helper;

import java.security.cert.X509Certificate;

import javax.net.ssl.X509TrustManager;

/**
 * Created by benchengzhou on 2017/11/13  10:09 .
 * 作者邮箱: mappstore@163.com
 * 功能描述: 测试环境添加https全部信任
 * 类    名: TrustAllCerts
 * 备    注:
 */


public class TrustAllCerts implements X509TrustManager {
    @Override
    public void checkClientTrusted(X509Certificate[] chain, String authType) {}

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

    @Override
    public X509Certificate[] getAcceptedIssuers() {return new X509Certificate[0];}
}
  • OK!剩下的就是慢慢的使用吧go

好了问题解决了放过来看一下原理:

查阅文档我们发现OKhttp是可以对下载器进行设置的,也就是提供给我们了指定或自定义下载器的可能,文档有这句话

downloader(Downloader downloader) :
容许使用自定义的下载器,可以用okhttp或者volley,必须实现Downloader接口。



这是文章的链接 有兴趣的同学可以研究一下,这里不做深究

正是因为如此,我们可以如下实现

picassoBuilder.downloader(new ImageDownLoader(client));



指定使用OKhttp作为网络下载器,故而问题转接成为只要可以实现okhttp可以实现 https的请求我们的Picasso就可以完成加载https的图片了
如果想要看OKhttp实现https请求请移步我的博客

  • 当然我现在项目的build配置如下,:
    compile ‘com.squareup.okhttp3:okhttp:3.5.0’
    compile ‘com.squareup.picasso:picasso:2.3.2’