转眼间谷歌的Glide图片加载库都4.8.0了,时间过得真的太快。
今天解决两个问题(第1个是独立问题,第2个依赖第1个):
1、Glide网络加载库(其默认为原生的API实现)集成为OkHttp,众所周知OkHttp可以帮助我们更方便地玩转网络请求;
2、让Glide可以加载https前缀的图片链接(如果你的域名证书是服务端自己瞎签的,没有认证,就过不了安全检查,表现为你用Chrome浏览器打开这个链接会提示不安全的红色警告)。

问题1:集成OkHttp

一般来说我们项目一开始会分别使用Glide和OkHttp库,没特殊需求时没想到过它们还要结合。
首先,假设我们已经有OkHttpClient的初始化逻辑了:

1
2
3
4
5
6
7
8
// 简化示意的初始化代码
public static OkHttpClient getHttpClient() {
OkHttpClient.Builder builder = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.addInterceptor(...)
.cache(...);
return builder.build();
}

然后我们配置一下必要的依赖库,在app的gradle文件中:

1
2
3
4
5
6
7
8
dependencies {
implementation 'com.squareup.okhttp3:okhttp:3.11.0'
...
implementation 'com.github.bumptech.glide:glide:4.8.0'
implementation 'com.github.bumptech.glide:okhttp3-integration:4.8.0' // 新增
implementation 'com.github.bumptech.glide:annotations:4.8.0' // 新增
annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0'
}

由于我还使用了Retrofit配合OKHttp,这里就省略了哈,主要关注Glide相关的库(集成和注解)。
如果用到了混淆,记得配置一下Proguard:

1
2
3
4
5
6
7
# For Glide ---->
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public class * extends com.bumptech.glide.module.AppGlideModule
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
**[] $VALUES;
public *;
}

配置完了记得Sync一下项目,接着新建一个AppGlideModule的子类,用我们现有的HttpClient来替换Glide的,很简单,这里把import的包也指明,方便对照:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import android.content.Context;
import android.support.annotation.NonNull;

import com.bumptech.glide.Glide;
import com.bumptech.glide.Registry;
import com.bumptech.glide.annotation.GlideModule;
import com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader;
import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.module.AppGlideModule;

import java.io.InputStream;

// 注意这个注解一定要加上,HttpGlideModule是自定义的名字
@GlideModule
public final class HttpGlideModule extends AppGlideModule {

@Override
public void registerComponents(@NonNull Context context, @NonNull Glide glide, @NonNull Registry registry) {
// 注意这里用我们刚才现有的Client实例传入即可
registry.replace(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory(XXX.getHttpClient()));
}
}

OK,现在再用Glide去加载图片,就是走的OkHttpClient了,可以添加log拦截器去看,这里就不赘述了。

问题2:忽略安全证书加载https图片

主要是通过给OkHttp增加SSL和验证器配置来实现忽略安全认证,即便是自己签名证书的https域名也可以加载了。
先定义好SSLSocketFactory和HostnameVerifier:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/**
* getSSLSocketFactory、getTrustManagers、getHostnameVerifier
* 使OkHttpClient支持自签名证书,避免Glide加载不了Https图片
*/
private static SSLSocketFactory getSSLSocketFactory() {
try {
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, getTrustManagers(), new SecureRandom());
return sslContext.getSocketFactory();
} catch (Exception e) {
throw new RuntimeException(e);
}
}

private static TrustManager[] getTrustManagers() {
return new TrustManager[]{new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) {
}

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

@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[]{};
}
}};
}

private static HostnameVerifier getHostnameVerifier() {
return new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true; // 直接返回true,默认verify通过
}
};
}

最后回到最开始的初始化OkHttp代码,添加:

1
2
3
4
5
6
7
8
// 简化示意的初始化代码
public static OkHttpClient getHttpClient() {
OkHttpClient.Builder builder = new OkHttpClient.Builder()
...
.sslSocketFactory(getSSLSocketFactory())
.hostnameVerifier(getHostnameVerifier());
return builder.build();
}

大功告成了,虽然这样不是很安全的做法,但对于一些小项目或者测试环境来说,这能避免证书带来的无法加载网络图片的额外问题。