Glide入門教程——17.Glide Module 案例: 接受自簽名HTTPS證書

Glide Module 案例: 接受自簽名HTTPS證書

原文:Glide Module Example: Self-Signed HTTPS Network Stack
作者:Norman Peitek
翻譯:Dexter0218

在上一篇Glide的文章中,你已經學了GlideModule的基礎知識。他們提供了一個簡單的方法去訪問Glide核心部分的功能。你可以很快地通過實現和定義GlideModule改變Glide的行為。我們已經通過實現applyOptions()方法改變解析格式,去提升圖片質量。文本,我們要使用其他的方法,registerComponents(),去改變Glide的網絡棧,讓它能從自簽名HTTPS服務器接收連接和圖片。

Glide 系列概覽

  1. 入門簡介
  2. 高級加載
  3. 適配器(ListView, GridView)
  4. 占位圖& 淡入淡出動畫
  5. 圖片大小 & 縮放
  6. 播放GIF & 視頻
  7. 緩存基礎
  8. 請求優先級
  9. 縮略圖
  10. 回調:定制view中使用SimpleTarget和ViewTarget
  11. 通知欄和桌面小控件的圖片加載
  12. 異常: 調試和報錯處理
  13. 自定義變換
  14. 用animate()定制動畫
  15. 整合網絡協議棧
  16. 用Modules定制Glide
  17. Glide Module 案例: 接受自簽名HTTPS證書
  18. Glide Module 案例: 自定義緩存
  19. Glide Module 案例: 通過加載自定義大小圖片優化
  20. 動態使用 Model Loaders
  21. 如何旋轉圖片
  22. 系列綜述

用GlideModule定制Glide

在看下面的之前,請確保你看完并理解了前面文章關于GlideModules部分。我們不會在本文中再次回顧基礎,而是直接跳到問題。所以確保你打好GlideModule的基礎。

你已經知道GlideModule提供了兩個方法改變行為。上篇文章,我們學習了第一個方法applyOption()。本文我們使用另一個方法registerComponents()去設置一個不同的網絡棧。默認地,Glide內部使用標準的HTTPUrlConnection去下載圖片。Glide也提供兩個集成庫。這三個方法優點是在安全設置上都是相當嚴格的。唯一的不足之處是當你從一個使用HTTPS,還是self-signed的服務器下載圖片時,Glide并不會下載或者顯示圖片,因為self-signed認證會被認為存在安全問題。

不安全的 OkHttpClient

這樣,你會需要去實現能夠接受self-signed認證的網絡棧。幸運地,我們已經實現并用過一個“不安全的”OkHttpClient。由于它提供給了一個需要集成的常規OkHttpClient,我們只需要拷貝并粘貼這個類:

public class UnsafeOkHttpClient {  
    public static OkHttpClient getUnsafeOkHttpClient() {
        try {
            // Create a trust manager that does not validate certificate chains
            final TrustManager[] trustAllCerts = new TrustManager[]{
                    new X509TrustManager() {
                        @Override
                        public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                        }

                        @Override
                        public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                        }

                        @Override
                        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                            return new X509Certificate[0];
                            //return null;//刪除這行,多謝下面評論的幾位小伙伴指出空指針問題,并提供解決方案。
                        }
                    }
            };

            // Install the all-trusting trust manager
            final SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());

            // Create an ssl socket factory with our all-trusting manager
            final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

            OkHttpClient okHttpClient = new OkHttpClient();
            okHttpClient.setSslSocketFactory(sslSocketFactory);
            okHttpClient.setProtocols(Arrays.asList(Protocol.HTTP_1_1));
            okHttpClient.setHostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });

            return okHttpClient;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

創建的OkHttpClient關閉了所有的SSL認證檢查。

集成到 Glide

Glide的OkHTTP集成庫做的都是一樣的工作,所以我們可以跟隨他們的步驟。首先,我們需要在GlideModule里聲明我們的定制。你應該想到,我們需要在registerComponents()方法里做適配。我們可以調用.register()方法去交換Glide基礎構成。Glide使用一個ModelLoader去鏈接到數據模型創建一個具體的數據類型。我們的例子中,我們需要創建一個ModelLoader,它連接到一個URL,通過GlideUrl類響應并轉化為輸入流。Glide需要能夠創建我們的新ModelLoader的實例,所以我們在.register()方法中傳入一個工廠:

public class UnsafeOkHttpGlideModule implements GlideModule {  
        @Override
        public void applyOptions(Context context, GlideBuilder builder) {

        }

        @Override
        public void registerComponents(Context context, Glide glide) {
            glide.register(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory());
        }
    }

方法里的前兩個參數是模型類和鏈接資源類。最后一個參數是ModelLoaderFactory。最終,我們不能直接設置一個UnsafeOkHttpClient實例,我們需要創建一個ModelLoaderFactory,使用UnsafeOkHttpClient去提供URL和輸入流之間的鏈接。

再次,OkHttp集成庫給了我們一個很棒的模版:

public class OkHttpUrlLoader implements ModelLoader<GlideUrl, InputStream> {

    /**
     * The default factory for {@link OkHttpUrlLoader}s.
     */
    public static class Factory implements ModelLoaderFactory<GlideUrl, InputStream> {
        private static volatile OkHttpClient internalClient;
        private OkHttpClient client;

        private static OkHttpClient getInternalClient() {
            if (internalClient == null) {
                synchronized (Factory.class) {
                    if (internalClient == null) {
                        internalClient = UnsafeOkHttpClient.getUnsafeOkHttpClient();
                    }
                }
            }
            return internalClient;
        }

        /**
         * Constructor for a new Factory that runs requests using a static singleton client.
         */
        public Factory() {
            this(getInternalClient());
        }

        /**
         * Constructor for a new Factory that runs requests using given client.
         */
        public Factory(OkHttpClient client) {
            this.client = client;
        }

        @Override
        public ModelLoader<GlideUrl, InputStream> build(Context context, GenericLoaderFactory factories) {
            return new OkHttpUrlLoader(client);
        }

        @Override
        public void teardown() {
            // Do nothing, this instance doesn't own the client.
        }
    }

    private final OkHttpClient client;

    public OkHttpUrlLoader(OkHttpClient client) {
        this.client = client;
    }

    @Override
    public DataFetcher<InputStream> getResourceFetcher(GlideUrl model, int width, int height) {
        return new OkHttpStreamFetcher(client, model);
    }
}

在這個類里,你可以看到ModelLoaderFactory是如何被構造的。對我們來說,最重要的一行是internalClient對象的創建:internalClient = UnsafeOkHttpClient.getUnsafeOkHttpClient();

不幸地是,我們仍然要使用我們不安全的OkHttpClient去鏈接Url到一個有效的輸入流。這樣,我們需要另外一個類去取到URL對應的輸入流的響應:

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) {
            try {
                responseBody.close();
            } catch (IOException e) {
                // Ignored.
            }
        }
    }

    @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
    }
}

你沒必要明白類里面的所有細節。相反,你應當對于Glide系統如何替換內部工廠部分有個概述。

展望

本文中,你已經看了另一個改變Glide工作方式使用案例。我們已經實現了一個“不安全”的網絡棧,并且用GlideModule的registerComponents()集成它到Glide內。但那也僅是Glide可修改內容的冰山一角。

下篇文章,我們會學習另一個使用GlideModule去改變Glide緩存方式的案例。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容