添加okhttp的https

okhttp在android开发中使用已经很普遍。在android5.0以下版本使用okhttp时,如果需要使用https,需要指定支持tls1.1和tls1.2版本。

我们可以用google查到很多"解决方法",其实根本没那么复杂,实现本身比较简单,关键在于**读源码 **。
OkHttpClient内推荐使用public Builder sslSocketFactory(SSLSocketFactory sslSocketFactory, X509TrustManager trustManager),而public Builder sslSocketFactory(SSLSocketFactory sslSocketFactory)这个方法已经被打上了@deprecated

/**
     * Sets the socket factory used to secure HTTPS connections. If unset, the system default will
     * be used.
     *
     * @deprecated {@code SSLSocketFactory} does not expose its {@link X509TrustManager}, which is
     *     a field that OkHttp needs to build a clean certificate chain. This method instead must
     *     use reflection to extract the trust manager. Applications should prefer to call {@link
     *     #sslSocketFactory(SSLSocketFactory, X509TrustManager)}, which avoids such reflection.
     */

原因是如果不提供X509TrustManager, okhttp会使用反射的方法创建一个空的证书链。

其实X509TrustManagerSSLSocketFactory已经提供了现成的方法,只不过是private的,copy出来就可以了

private X509TrustManager systemDefaultTrustManager() {
    try {
      TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
          TrustManagerFactory.getDefaultAlgorithm());
      trustManagerFactory.init((KeyStore) null);
      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];
    } catch (GeneralSecurityException e) {
      throw new AssertionError(); // The system has no TLS. Just give up.
    }
  }

  private SSLSocketFactory systemDefaultSslSocketFactory(X509TrustManager trustManager) {
    try {
      SSLContext sslContext = SSLContext.getInstance("TLS");
      sslContext.init(null, new TrustManager[] { trustManager }, null);
      return sslContext.getSocketFactory();
    } catch (GeneralSecurityException e) {
      throw new AssertionError(); // The system has no TLS. Just give up.
    }
  }

我们唯一需要做的就是创建一个SSLSocketFactory的代理类, 通过代理设置SSLSocket的TLS版本吗,然后使用代理类替换默认的SSLSocketFactory。
完整代码如下:

private X509TrustManager systemDefaultTrustManager() {
    try {
      TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
          TrustManagerFactory.getDefaultAlgorithm());
      trustManagerFactory.init((KeyStore) null);
      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];
    } catch (GeneralSecurityException e) {
      throw new AssertionError(); // The system has no TLS. Just give up.
    }
  }

  private SSLSocketFactory sslSocketFactory(X509TrustManager trustManager) {
    try {
      SSLContext sslContext = SSLContext.getInstance("TLS");
      sslContext.init(null, new TrustManager[] { trustManager }, null);
      return new TLSSocketFactory(sslContext.getSocketFactory());
    } catch (GeneralSecurityException e) {
      throw new AssertionError(); // The system has no TLS. Just give up.
    }
  }

public OkHttpClient.Builder compactTls(OkHttpClient.Builder client) {
        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
            try {
                X509TrustManager trustManager = systemDefaultTrustManager();
                SSLSocketFactory sslSocketFactory = sslSocketFactory(trustManager);
                client.sslSocketFactory(sslSocketFactory, trustManager);
            } catch (Exception exc) {
                logger.error("Error while setting TLS compact", exc);
            }
        }

        return client;
    }
public class TLSSocketFactory extends SSLSocketFactory {
    private static final String[] TLS_V1_V2 = {"TLSv1.1", "TLSv1.2"};

    final SSLSocketFactory delegate;

    public TLSSocketFactory(SSLSocketFactory base) {
        this.delegate = base;
    }

    @Override
    public String[] getDefaultCipherSuites() {
        return delegate.getDefaultCipherSuites();
    }

    @Override
    public String[] getSupportedCipherSuites() {
        return delegate.getSupportedCipherSuites();
    }

    @Override
    public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
        return patch(delegate.createSocket(s, host, port, autoClose));
    }

    @Override
    public Socket createSocket(String host, int port) throws IOException {
        return patch(delegate.createSocket(host, port));
    }

    @Override
    public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
        return patch(delegate.createSocket(host, port, localHost, localPort));
    }

    @Override
    public Socket createSocket(InetAddress host, int port) throws IOException {
        return patch(delegate.createSocket(host, port));
    }

    @Override
    public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
        return patch(delegate.createSocket(address, port, localAddress, localPort));
    }

    private Socket patch(Socket s) {
        if (s != null && s instanceof SSLSocket) {
            ((SSLSocket) s).setEnabledProtocols(TLS_V1_V2);
        }
        return s;
    }
}

你可能感兴趣的:(添加okhttp的https)