解決Glide加載自簽名的https圖片時失敗問題

前言


在android應(yīng)用中,Glide這個工具庫想必大家已經(jīng)很熟悉了,它主要是用來加載和顯示圖片的。最近項目服務(wù)器url由http切換到https,所有使用Glide加載網(wǎng)絡(luò)圖片的地方都失敗,原因是Glide默認是http請求。

也就是說,想用Gilde加載自簽名的https圖片,必須修改Glide加載圖片的方法。本文通過使用okhttp信任自簽名證書的方法來修改GlideModule來實現(xiàn)。

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}.
*
* <p>
*     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}.
* </p>
*/
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<InputStream> {
    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<String, String> 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<InputStream> {
    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<String, String> 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<? extends Certificate> 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'
 <meta-data
            android:name="com.test.http.OkHttpGlideModule"
            android:value="GlideModule"/>

5.加載圖片(加載失敗時重試)


 Glide.with(PhotoActivity.this)
                .load(url)
                .asBitmap()
                .listener(new RequestListener<String, Bitmap>() {
                    @Override
                    public boolean onException(Exception e, String model, Target<Bitmap> 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<Bitmap> target, boolean isFromMemoryCache, boolean isFirstResource) {
                        return false;
                    }
                })
                .into(photoView);

最近項目中正好遇到這個問題,記錄下來跟大家分享,歡迎交流!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一、簡介 在泰國舉行的谷歌開發(fā)者論壇上,谷歌為我們介紹了一個名叫Glide的圖片加載庫,作者是bumptech。這...
    天天大保建閱讀 7,753評論 2 28
  • Glide筆記 一、簡介 在泰國舉行的谷歌開發(fā)者論壇上,谷歌為我們介紹了一個名叫Glide的圖片加載庫,作者是bu...
    AndroidMaster閱讀 4,077評論 0 27
  • 7.1 壓縮圖片 一、基礎(chǔ)知識 1、圖片的格式 jpg:最常見的圖片格式。色彩還原度比較好,可以支持適當壓縮后保持...
    AndroidMaster閱讀 2,691評論 0 13
  • 學習來源:郭霖大師博客地址 1、圖片加載框架挺多,如Volley、Glide、Picasso、Fresco、本次是...
    子謙寶寶閱讀 1,825評論 0 6
  • 第一次見他是18年前的深秋,他穿著黃色的夾克,和當時的季節(jié)很配??赡菚r候的他眼里只有她...... “...
    瘋子707閱讀 657評論 0 0

友情鏈接更多精彩內(nèi)容