前言

在Android开发中,Okhttp想必大家都不陌生,一个处理网络请求的开源项目,是安卓端最火热的轻量级框架。

本人在开发过程中也用了很长一段时间了,但是基本请求的都是http接口。即使访问https网站也都是绿色的,有个很特殊的大型购票网站则不是,所以本文主要介绍如何使用Okhttp访问自签名证书的https接口。而且公司自己服务接口也全部换成了https接口,在去年就说ios要强制更换https接口,不然appstore无法上架,最近好像也没信了,估计是政策放宽了吧。不管怎样,今天就拿这个大型购票网站举例来说,使用Okhttp访问购票网站。

获取签名证书

购票网站的签名证书可以在官网上直接下载,或者点击这里下载即可。srca.cer即为购票网站的签名证书。

为了方便将签名证书添加到OkHttp中,可以将签名证书放在本地的assets文件夹下,为了便于管理我放在了assets/cers目录下,在代码中可以通过流的形式获取到证书文件。

添加证书一般是在访问接口之前添加,为了方便,我放在了Application中,这样的话,在应用启动的时候就会已经将添加添加到了OkHttp中。

使用Okhttp访问接口

  • 使用Android Studio的话,直接添加Okhttp的依赖:
compile 'com.squareup.okhttp3:okhttp:3.3.1'
  • 获取签名证书文件流
//获取证书流
private void readHttpsCer() {
        try {
            InputStream is = getAssets().open("cers/srca.cer");
            NetConfig.addCertificate(is); // 这里将证书读取出来,,放在配置中byte[]里
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
    }
  • NetConfig相关代码:
// 证书数据
    private static List<byte[]> CERTIFICATES_DATA = new ArrayList<>();

    /**
     * 添加https证书
     *
     * @param inputStream
     */
    public synchronized static void addCertificate(InputStream inputStream) {
        Log.i(TAG, "#addCertificate inputStream = " + inputStream);
        if (inputStream != null) {

            try {
                int ava = 0;// 数据当次可读长度
                int len = 0;// 数据总长度
                ArrayList<byte[]> data = new ArrayList<>();
                while ((ava = inputStream.available()) > 0) {
                    byte[] buffer = new byte[ava];
                    inputStream.read(buffer);
                    data.add(buffer);
                    len += ava;
                }

                byte[] buff = new byte[len];
                int dstPos = 0;
                for (byte[] bytes : data) {
                    int length = bytes.length;
                    System.arraycopy(bytes, 0, buff, dstPos, length);
                    dstPos += length;
                }

                CERTIFICATES_DATA.add(buff);
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }

    /**
     * https证书
     *
     * @return
     */
    public static List<byte[]> getCertificatesData() {
        return CERTIFICATES_DATA;
    }
  • 编写工具类,将证书添加到OkHttp中:
public static OkHttpClient createOkHttp() {

        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        // 添加证书
        List<InputStream> certificates = new ArrayList<>();
        List<byte[]> certs_data = NetConfig.getCertificatesData();

        // 将字节数组转为数组输入流
        if (certs_data != null && !certs_data.isEmpty()) {
            for (byte[] bytes : certs_data) {
                certificates.add(new ByteArrayInputStream(bytes));
            }
        }


        SSLSocketFactory sslSocketFactory = getSocketFactory(certificates);
        if (sslSocketFactory != null) {
            builder.sslSocketFactory(sslSocketFactory);
        }

        return builder.build();
    }


    /**
     * 添加证书
     *
     * @param certificates
     */
    private static SSLSocketFactory getSocketFactory(List<InputStream> certificates) {
        try {
            CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(null);
            try {
                for (int i = 0, size = certificates.size(); i < size; ) {
                    InputStream certificate = certificates.get(i);
                    String certificateAlias = Integer.toString(i++);
                    keyStore.setCertificateEntry(certificateAlias, certificateFactory
                            .generateCertificate(certificate));
                    if (certificate != null)
                        certificate.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

            SSLContext sslContext = SSLContext.getInstance("TLS");
            TrustManagerFactory trustManagerFactory =
                    TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(keyStore);
            sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());
            return sslContext.getSocketFactory();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
  • 查看测试使用结果:

将自签名证书添加到Okhttp中,通过创建的OkHttpClient对象,我们就可以访问相关的Https接口服务了。