一直以来并没有升级项目的OkHttp版本,直到昨天上线遇到一个bug:http://stackoverflow.com/questions/27687907/android-os-networkonmainthreadexception-using-rxjava-on-android
按照stackOverflow的方法,可以在unsubscribe的时候可以这样:
subscribeOn(Schedulers.newThread()).observeOn(AndroidSchedulers.mainThread()).subscribe()
但是仍旧觉得不够优雅,于是继续探踪寻迹:
https://github.com/square/retrofit/issues/1328
最后大神说,已经在最新的okhttp中解决了,于是决定升级项目的okhttp版本。
okhttp3.x****和****okhttp2.x****的****api不同
okhttp3.x在架构上转换为使用Builder模式进行相关配置。
好处:
可以在任何地方对OkHttpClient进行配置
mOkHttpClient = RetrofitUtil.setSSL().newBuilder()
上面setSSL
中生成了一个OkhttpClient对象,而newBuilder()
:
public Builder newBuilder() {
return new Builder(this);
}
能直接获取到一个新的Builder对象,以方便进行配置的继续。
使用https进行访问时,默认信任所有的证书的书写方式
- okHttp2.x:
/**
* 设置https 访问的时候对所有证书都进行信任
*
* @throws Exception
*/
protected void setSSL() throws Exception {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, new TrustManager[]{new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}}, new SecureRandom());
mOkHttpClient.setSslSocketFactory(sc.getSocketFactory());
mOkHttpClient.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
}
- okHttp3.x
/**
* 设置https 访问的时候对所有证书都进行信任
*
* @throws Exception
*/
public static OkHttpClient setSSL() throws Exception {
final X509TrustManager trustManager = new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
};
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, new TrustManager[]{trustManager}, new SecureRandom());
SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
return new OkHttpClient.Builder()
.sslSocketFactory(sslSocketFactory, trustManager)
.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
})
.build();
}
这里需要注意的是,okHttp中关于sslSocketFactory()
有两个重载方法:
/**
* 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.
*/
public Builder sslSocketFactory(SSLSocketFactory sslSocketFactory) {
if (sslSocketFactory == null) throw new NullPointerException("sslSocketFactory == null");
X509TrustManager trustManager = Platform.get().trustManager(sslSocketFactory);
if (trustManager == null) {
throw new IllegalStateException("Unable to extract the trust manager on " + Platform.get()
+ ", sslSocketFactory is " + sslSocketFactory.getClass());
}
this.sslSocketFactory = sslSocketFactory;
this.certificateChainCleaner = CertificateChainCleaner.get(trustManager);
return this;
}
但是该方法已经被官方deprecated
了,原因在其推荐的重载方法中写的明白:
/**
* Sets the socket factory and trust manager used to secure HTTPS connections. If unset, the
* system defaults will be used.
*
* <p>Most applications should not call this method, and instead use the system defaults. Those
* classes include special optimizations that can be lost if the implementations are decorated.
*
* <p>If necessary, you can create and configure the defaults yourself with the following code:
*
* <pre> {@code
*
* 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));
* }
* X509TrustManager trustManager = (X509TrustManager) trustManagers[0];
*
* SSLContext sslContext = SSLContext.getInstance("TLS");
* sslContext.init(null, new TrustManager[] { trustManager }, null);
* SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
*
* OkHttpClient client = new OkHttpClient.Builder()
* .sslSocketFactory(sslSocketFactory, trustManager);
* .build();
* }</pre>
*/
public Builder sslSocketFactory(
SSLSocketFactory sslSocketFactory, X509TrustManager trustManager) {
if (sslSocketFactory == null) throw new NullPointerException("sslSocketFactory == null");
if (trustManager == null) throw new NullPointerException("trustManager == null");
this.sslSocketFactory = sslSocketFactory;
this.certificateChainCleaner = CertificateChainCleaner.get(trustManager);
return this;
}
混淆
1、okhttp3.x相较于okhttp2.x,proguard需要作出相应的修改:
https://github.com/square/okhttp/issues/2230
这里大神给了如何对okhttp3.x进行混淆
2、这里出现了一下小插曲,项目中更新proguard时,将com.squareup.okhttp.**
这段也删了,但是项目中有用到picasso
,而picasso
用到了okhttp
,所以需要保持其中的okhttp不被混淆。