Android retrofit2 https 使用示例

最近笔者公司有需要用到https协议的方式来做项目,所以记录一下,希望以后能回顾一下

什么是https协议,在这里我也不详细说明,你可以去了解一下

1.我们先分析一下,如果我们需要用到https,有哪些地方需要做处理
1)Retrofit 请求服务数据
Retrofit 中的证书锁定同样是借助OkHttpClient实现的:通过为OkHttpClient添加CertificatePinner即可。CertificatePinner对象以构建器的方式创建,可以通过其add()方法来锁定多个证书。

public class OkHttpClientManager {
    public static void setCertificates( InputStream... certificates) {
        try {
            CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(null);
            int index = 0;
            for (InputStream certificate : certificates) {
                String certificateAlias = Integer.toString(index++);
                keyStore.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(certificate));

                try {
                    if (certificate != null)
                        certificate.close();
                } catch (IOException e) {
                }
            }

//            SSLContext sslContext = SSLContext.getInstance("TLS");
//
//            TrustManagerFactory trustManagerFactory =
//                    TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
//
//            trustManagerFactory.init(keyStore);
//            sslContext.init
//                    (
//                            null,
//                            trustManagerFactory.getTrustManagers(),
//                            new SecureRandom()
//                    );
//            mOkHttpClient.sslSocketFactory(sslContext.getSocketFactory());
//
//
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //获取这个SSLSocketFactory
    public static SSLSocketFactory getSSLSocketFactory() {
        try {
            SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, getTrustManager(), new SecureRandom());
            return sslContext.getSocketFactory();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    //获取TrustManager
    private static TrustManager[] getTrustManager() {
        TrustManager[] trustAllCerts = new TrustManager[]{
                new X509TrustManager() {

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

                    @Override
                    public void checkClientTrusted(X509Certificate[] chain,
                                                   String authType) throws CertificateException {
                    }

                    @Override
                    public void checkServerTrusted(X509Certificate[] chain,
                                                   String authType) throws CertificateException {
                    }
                }
        };
        return trustAllCerts;
    }

    //获取HostnameVerifier
    public static HostnameVerifier getHostnameVerifier() {
        HostnameVerifier hostnameVerifier = new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        };
        return hostnameVerifier;
    }
}

【Application】

 @Override
    public void onCreate() {
        super.onCreate();
        try {
            OkHttpClientManager.setCertificates(getAssets().open("AlphaSSLRootCA.cer"), getAssets().open("mediadRootCA.cer"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

【在请求服务前调用认证证书】

    public static OkHttpClient defaultOkHttpClient() {
        OkHttpClient.Builder mOkHttpClient = new OkHttpClient.Builder();
       mOkHttpClient.sslSocketFactory(OkHttpClientManager.getSSLSocketFactory());//添加证书
        mOkHttpClient.writeTimeout(30 * 1000, TimeUnit.MILLISECONDS);
        mOkHttpClient.readTimeout(10 * 1000, TimeUnit.MILLISECONDS);
        mOkHttpClient.connectTimeout(10 * 1000, TimeUnit.MILLISECONDS);

        //设置缓存路径
        File httpCacheDirectory = new File(app.getCacheDir(), "okhttpCache");
        //设置缓存 10M
        Cache cache = new Cache(httpCacheDirectory, 10 * 1024 * 1024);
        mOkHttpClient.cache(cache);
        //设置拦截器
        mOkHttpClient.addInterceptor(LoggingInterceptor);
        mOkHttpClient.addNetworkInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR);
        mOkHttpClient.addInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR);
        return mOkHttpClient.build();
    }

2)Glide 图片加载
Glide 使用的自己的网络请求来加载的图片,想要用glide访问https图片,就必须替换掉glide原始加载图片的方法,使其同样做到信任所有证书。

首先重新GlideModule,ModelLoader,DataFetcher

【DataFetcher】

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) {
            }
        }
        if (responseBody != null) {
            responseBody.close();
        }
    }

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

    @Override
    public void cancel() {
    }
}

【ModelLoader】

public class OkHttpUrlLoader implements ModelLoader<GlideUrl, InputStream> {

    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 = new OkHttpClient();
                    }
                }
            }
            return internalClient;
        }

        public Factory() {
            this(getInternalClient());
        }

        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() {
        }
    }

    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);
    }
}

【GlideModule】

public class OkHttpGlideModule implements GlideModule {
    @Override
    public void applyOptions(Context context, GlideBuilder builder) {
        // Do nothing.
    }

    @Override
    public void registerComponents(Context context, Glide glide) {
        OkHttpClient mHttpClient = new OkHttpClient().newBuilder()
                .sslSocketFactory(OkHttpClientManager.getSSLSocketFactory())
                .hostnameVerifier(OkHttpClientManager.getHostnameVerifier())
                .build();
        glide.register(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory(mHttpClient));
    }
}

【AndroidManifes.xml】

 <meta-data
  android:name="包名.OkHttpGlideModule"
  android:value="GlideModule" />

3)WebView 数字证书
WebView组件加载网页发生证书认证错误时,会调用WebViewClient类的onReceivedSslError方法,在这个方法里,可以点击源码看到SslErrorHandler中有两个主要的方法(我这里使用了Tencent X5 浏览器)
cancel( )
停止加载问题页面

proceed( )
忽略SSL证书错误,继续加载页面(不推荐)

既然用到了https,我们大部分时候都是为了网络安全问题
所以,可以定义一个类来验证证书安全

//获取webz证书
    private static OkHttpClient.Builder setWebCertificates(OkHttpClient.Builder client) {
        try {
            SSLSocketFactory sslSocketFactory = OkHttpClientManager.getSSLSocketFactory();
            X509TrustManager trustManager = Platform.get().trustManager(sslSocketFactory);
            client.sslSocketFactory(sslSocketFactory, trustManager);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return client;
    }
    
// 验证证书
    public static void webCertificateOfVerification(final SslErrorHandler handler, String url) {
        OkHttpClient.Builder builder = OkHttpClientManager.setWebCertificates(new OkHttpClient.Builder());
        Request request = new Request.Builder().url(url)
                .build();
        builder.build().newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                Log.e("验证失败", e.getMessage());
                handler.cancel();
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                Log.e("验证成功", response.body().string());
                handler.proceed();
            }
        });
    }

onReceivedSslError中的代码

private WebViewClient client = new WebViewClient() {
        /**
         * 防止加载网页时调起系统浏览器
         */
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            view.loadUrl(url);
            return true;
        }

        /**
         * 处理ssl
         * @param webView
         * @param sslErrorHandler
         * @param sslError
         */
        @Override
        public void onReceivedSslError(WebView webView, SslErrorHandler sslErrorHandler, SslError sslError) {
            OkHttpClientManager.webCertificateOfVerification(sslErrorHandler, webView.getUrl());
        }
    };

本文结合大神的文章以及自己的理解,有问题欢迎指出,共同学习

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值