解决Glide加载自签名的https图片时失败问题

前言


在android应用中,Glide这个工具库想必大家已经很熟悉了,它主要是用来加载和显示图片的。最近项目服务器url由http切换到https,所有使用Glide加载网络图片的地方都失败,原因是Glide默认是http请求。

也就是说,想用Gilde加载自签名的https图片,必须修改Glide加载图片的方法。本文通过使用okhttp信任自签名证书的方法来修改GlideModule来实现。

1.下载com.github.bumptech.glide:okhttp.integration:1.4.0@aar包

可以通过在buile.gradle中添加依赖com.github.bumptech.glide:okhttp-integration:1.4.0@aar下载,下载后的文件在 “C盘/用户/用户名/.gradle/caches/modules-2/files-2.1下面”(下载完后记得把依赖删掉)

2.拷贝其中三个类OkHttpGlideModule,OkHttpUrlLoader,OkHttpStreamFetcher到工程中


OkHttpGlideModule.class


import android.content.Context;
import com.bumptech.glide.Glide;
import com.bumptech.glide.GlideBuilder;
import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.module.GlideModule;
import com.changhong.park.pda.utils.HTTPSUtils;

import java.io.InputStream;

/**
* A {@link GlideModule} implementation to replace Glide's default
* {@link java.net.HttpURLConnection} based {@link com.bumptech.glide.load.model.ModelLoader} with an OkHttp based
* {@link com.bumptech.glide.load.model.ModelLoader}.
*
* 

* If you're using gradle, you can include this module simply by depending on the aar, the module will be merged * in by manifest merger. For other build systems or for more more information, see * {@link GlideModule}. *

*/ public class OkHttpGlideModule implements GlideModule { @Override public void applyOptions(Context context, GlideBuilder builder) { // Do nothing. } @Override public void registerComponents(Context context, Glide glide) { glide.register(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory(new OKHttpUtils(context).getHttpClient())); } }

OkHttpStreamFetcher.class


import com.bumptech.glide.Priority;
import com.bumptech.glide.load.data.DataFetcher;
import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.util.ContentLengthInputStream;

import java.io.IOException;
import java.io.InputStream;
import java.util.Map;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;


/**
 * Fetches an {@link InputStream} using the okhttp library.
 */
public class OkHttpStreamFetcher implements DataFetcher {
    private final OkHttpClient client;
    private final GlideUrl url;
    private InputStream stream;
    private ResponseBody responseBody;

    public OkHttpStreamFetcher(OkHttpClient client, GlideUrl url) {
        this.client = client;
        this.url = url;
    }

    @Override
    public InputStream loadData(Priority priority) throws Exception {
        Request.Builder requestBuilder = new Request.Builder()
                .url(url.toStringUrl());

        for (Map.Entry headerEntry : url.getHeaders().entrySet()) {
            String key = headerEntry.getKey();
            requestBuilder.addHeader(key, headerEntry.getValue());
        }

        Request request = requestBuilder.build();

        Response response = client.newCall(request).execute();
        responseBody = response.body();
        if (!response.isSuccessful()) {
            throw new IOException("Request failed with code: " + response.code());
        }

        long contentLength = responseBody.contentLength();
        stream = ContentLengthInputStream.obtain(responseBody.byteStream(), contentLength);
        return stream;
    }

    @Override
    public void cleanup() {
        if (stream != null) {
            try {
                stream.close();
            } catch (IOException e) {
                // Ignored
            }
        }
        if (responseBody != null) {
            responseBody.close();
        }
    }

    @Override
    public String getId() {
        return url.getCacheKey();
    }

    @Override
    public void cancel() {
        // TODO: call cancel on the client when this method is called on a background thread. See #257
    }
}

OkHttpUrlLoader.class


import com.bumptech.glide.Priority;
import com.bumptech.glide.load.data.DataFetcher;
import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.util.ContentLengthInputStream;

import java.io.IOException;
import java.io.InputStream;
import java.util.Map;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;


/**
 * Fetches an {@link InputStream} using the okhttp library.
 */
public class OkHttpStreamFetcher implements DataFetcher {
    private final OkHttpClient client;
    private final GlideUrl url;
    private InputStream stream;
    private ResponseBody responseBody;

    public OkHttpStreamFetcher(OkHttpClient client, GlideUrl url) {
        this.client = client;
        this.url = url;
    }

    @Override
    public InputStream loadData(Priority priority) throws Exception {
        Request.Builder requestBuilder = new Request.Builder()
                .url(url.toStringUrl());

        for (Map.Entry headerEntry : url.getHeaders().entrySet()) {
            String key = headerEntry.getKey();
            requestBuilder.addHeader(key, headerEntry.getValue());
        }

        Request request = requestBuilder.build();

        Response response = client.newCall(request).execute();
        responseBody = response.body();
        if (!response.isSuccessful()) {
            throw new IOException("Request failed with code: " + response.code());
        }

        long contentLength = responseBody.contentLength();
        stream = ContentLengthInputStream.obtain(responseBody.byteStream(), contentLength);
        return stream;
    }

    @Override
    public void cleanup() {
        if (stream != null) {
            try {
                stream.close();
            } catch (IOException e) {
                // Ignored
            }
        }
        if (responseBody != null) {
            responseBody.close();
        }
    }

    @Override
    public String getId() {
        return url.getCacheKey();
    }

    @Override
    public void cancel() {
        // TODO: call cancel on the client when this method is called on a background thread. See #257
    }
}

3.添加信任自定义证书工具类,下面贴出重要方法


    public SSLSocketFactory getSSLSocketFactory(X509TrustManager trustManager) {
        SSLSocketFactory sslSocketFactory;
        try {

            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, new TrustManager[]{trustManager}, null);
            sslSocketFactory = sslContext.getSocketFactory();

        } catch (GeneralSecurityException e) {
            throw new RuntimeException(e);
        }
        return sslSocketFactory;

    }
   private X509TrustManager getX509TrustManager()
            throws GeneralSecurityException {
        InputStream inputStream = null;
        try {
            inputStream = mContext.getAssets().open("server.cer"); 
        }catch (IOException e){
            e.printStackTrace();
        }

        CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
        Collection certificates = certificateFactory.generateCertificates(inputStream);
        if (certificates.isEmpty()) {
            throw new IllegalArgumentException("expected non-empty set of trusted certificates");
        }

        // Put the certificates a key store.
        char[] password = "test".toCharArray(); // Any password will work.
        KeyStore keyStore = newEmptyKeyStore(password);
        int index = 0;
        for (Certificate certificate : certificates) {
            String certificateAlias = Integer.toString(index++);
            keyStore.setCertificateEntry(certificateAlias, certificate);
        }

        // Use it to build an X509 trust manager.
        KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(
                KeyManagerFactory.getDefaultAlgorithm());
        keyManagerFactory.init(keyStore, password);
        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
                TrustManagerFactory.getDefaultAlgorithm());
        trustManagerFactory.init(keyStore);
        TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
        if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
            throw new IllegalStateException("Unexpected default trust managers:"
                    + Arrays.toString(trustManagers));
        }
        return (X509TrustManager) trustManagers[0];
    }

4.builde.gradule 添加依赖 com.github.bumptech.glide:glide:3.7.0,在Androidmanifest中配置GlideModule(用自定义的替换默认的)


 compile 'com.github.bumptech.glide:glide:3.7.0'
 

5.加载图片(加载失败时重试)


 Glide.with(PhotoActivity.this)
                .load(url)
                .asBitmap()
                .listener(new RequestListener() {
                    @Override
                    public boolean onException(Exception e, String model, Target target, boolean isFirstResource) {
                       //加载失败时重试
                        handler.postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                loadPhoto(photoView,url);
                            }
                        }, 5000);
                        return false;
                    }

                    @Override
                    public boolean onResourceReady(Bitmap resource, String model, Target target, boolean isFromMemoryCache, boolean isFirstResource) {
                        return false;
                    }
                })
                .into(photoView);

最近项目中正好遇到这个问题,记录下来跟大家分享,欢迎交流!

你可能感兴趣的:(解决Glide加载自签名的https图片时失败问题)