okhttp3.2.0适配https,虽然网络上有很多文章。在此借助前人的经验,做一些处理。

虽然网上ok适配https 的文章一大堆。但是我在用
retrofit2 +Rxjava +Ok 的时候,由于IOS 那边需要适配https,也为了防止资讯页面的网页被运营商劫持。就开始做https 的适配。
发现网络上很多文章,经过一天的实践,发现我的不是请求不到数据,就是闪退,闪退的原因是项目集成了nuwa 热修复。app初始化的时候就请求服务器端的jar。在application类初始化之前请求没有
Content对象没获取到证书,好了 这里 废话不多说,请欣赏核心代码。
private static OkHttpClient myClient;
    static SSLSocketFactory sslSocketFactory = null;
    static X509TrustManager trustManager;

    public static OkHttpClient getOkHttpClient() {
        if (myClient == null) {
            try {
                SSLContext sslContext = trustManagerForCertificates(ttrustedCertificatesInputStream()); //SSLContext.getInstance("TLS");
//            setCard(ttrustedCertificatesInputStream());
                sslSocketFactory = sslContext.getSocketFactory();
            } catch (GeneralSecurityException e) {
                throw new RuntimeException(e);
            } catch (IOException e) {
                e.printStackTrace();
            }

            HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
            Interceptor mTokenInterceptor = new Interceptor() {//网络请求拦截器 这里是在所有网络请求的header里加上apikey
                @Override
                public Response intercept(Chain chain) throws IOException {
                    Request originalRequest = chain.request();
                    Request authorised = originalRequest.newBuilder().addHeader("head", "head").build();
                    return chain.proceed(authorised);
                }
            };

            myClient = new OkHttpClient.Builder().addInterceptor(interceptor).retryOnConnectionFailure(true).connectTimeout(15, TimeUnit.SECONDS).sslSocketFactory(sslSocketFactory).hostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {

                    return true;
                }
            }).addNetworkInterceptor(mTokenInterceptor).build();
        }
        return myClient;
    }

    public static OkHttpClient getOkHttpClient(Context cc) {
        if (myClient == null) {
            SSLContext sslContext = null; //SSLContext.getInstance("TLS");
            try {
                sslContext = trustManagerForCertificates(ttrustedCertificatesInputStream(cc));
                sslSocketFactory = sslContext.getSocketFactory();
            } catch (GeneralSecurityException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
//            setCard(ttrustedCertificatesInputStream(cc));
            HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
            Interceptor mTokenInterceptor = new Interceptor() {//网络请求拦截器 这里是在所有网络请求的header里加上apikey
                @Override
                public Response intercept(Chain chain) throws IOException {
                    Request originalRequest = chain.request();
                    Request authorised = originalRequest.newBuilder().addHeader("head", "head").build();//这儿的head为了上传头像的时候加的
                    return chain.proceed(authorised);
                }
            };
            myClient = new OkHttpClient.Builder().retryOnConnectionFailure(true).addInterceptor(interceptor).addNetworkInterceptor(mTokenInterceptor).sslSocketFactory(sslSocketFactory).hostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {

                    return true;
                }
            }).connectTimeout(15, TimeUnit.SECONDS).build();
        }
        return myClient;
    }

    private static InputStream ttrustedCertificatesInputStream(Context cc) {
        InputStream inputStream;
//这儿写工厂设计 根据url 打包不同的证书。是为了打包方便
        if (Config.APP_URL2.equals("你的线上服url")) {
            inputStream = cc.getResources().openRawResource(R.raw.线上服证书);

        } else if (Config.APP_URL2.equals("你的线上服url")) {
            inputStream = cc.getResources().openRawResource(R.raw.测试服证书);
        } else {
            inputStream = cc.getResources().openRawResource(R.raw.线上服证书);
        }
//这儿是最容易出问题的地方。网上好多地方直接 返回cc.getResources().openRawResource(R.raw.线上服证书)。我直接 这样做请求不到数据,而且只有一个certificate 对象  不知道各位有没有出现。所以在外面套了一个bufferread 来读取
       return new BufferedInputStream(inputStream);
//        return new BufferedInputStream(cc.getResources().openRawResource(R.raw.线上服证书));
//        return trustedCertificatesInputStream();
    }

    private static InputStream ttrustedCertificatesInputStream() {
        InputStream inputStream;
        if (Config.APP_URL2.equals("线上服url")) {
            inputStream = MyApplication.mContext.getResources().openRawResource(R.raw.线上服证书);

        } else if (Config.APP_URL2.equals("测试服url")) {
            inputStream = MyApplication.mContext.getResources().openRawResource(R.raw.测试服证书);
        } else {
            inputStream = MyApplication.mContext.getResources().openRawResource(R.raw.线上服证书);
        }

        return new BufferedInputStream(inputStream);
//        return trustedCertificatesInputStream();
    }


    private static SSLContext trustManagerForCertificates(InputStream in)
            throws GeneralSecurityException, IOException {
//        CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
// 这儿也是最容易出问题的,网上的大部分文章缺少后面的参数,。我把后面的 BC去掉,直接异常闪退。不知道各位有没有遇到。
        CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509", "BC");
        Collection<? extends Certificate> certificates = certificateFactory.generateCertificates(in);
        if (certificates.isEmpty()) {
            throw new IllegalArgumentException("expected non-empty set of trusted certificates");
        }

        char[] password = CLIENT_KET_PASSWORD.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);
        }
        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));
        }

        SSLContext ssContext = SSLContext.getInstance("SSL");
        ssContext.init(keyManagerFactory.getKeyManagers(), trustManagers, null);
        return ssContext;
    }

    private static KeyStore newEmptyKeyStore(char[] password) throws GeneralSecurityException {
        try {
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            InputStream in = null;
            keyStore.load(in, password);
            return keyStore;
        } catch (IOException e) {
            throw new AssertionError(e);
        }
    }

 
写两个是 因为 热修复 之前的 引导页需要获取 服务器的热修复jar 包,所以重写了一个方法。。。。谢谢观看。。。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值