package com.major.com.api;
import android.util.Log;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import okhttp3.ConnectionSpec;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okhttp3.TlsVersion;
import okio.Buffer;
import okio.BufferedSource;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
/**
* Created by QuietLake on 2017/11/3.
*/
public class LocalClient {
private static String BASE_URL= "";
private static Retrofit retrofit= null;
private static OkHttpClient okHttpClient= null;
private static LocalClient localCilent= null;
private LocalClient() {
}
// 单例获取
public static LocalClient getInstance(){
if (localCilent== null){
synchronized (LocalClient.class){
if (localCilent==null){
localCilent= new LocalClient();
}
}
}
return localCilent;
}
/**
* 重新设置baseUrl
* @parambaseUrl 需要在调用create之前调用
* @return当前对象
*/
public LocalClient setBaseUrl(String baseUrl) {
if (baseUrl.endsWith(File.separator)) {
BASE_URL= baseUrl;
} else {
BASE_URL= baseUrl + File.separator;
}
return localCilent;
}
//创建服务接口,不绑定生命周期
public T create(Class cla){
retrofit= getRetrofit();
return retrofit.create(cla);
}
private static final int READ_TIMEOUT = 60;
private static final int WRITE_TIMEOUT = 60;
private static final int CONNECT_TIMEOUT = 20;
//设置okhttpclient
private OkHttpClient initOkHttpClient(){
OkHttpClient.Builder builder= new OkHttpClient.Builder();
builder.readTimeout(READ_TIMEOUT, TimeUnit.SECONDS); //全局的读取超时时间
builder.writeTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS); //全局的写入超时时间
builder.connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS); //全局的连接超时时间
OkSSLSocketFactory okSSLSocketFactory= null;
try {
okSSLSocketFactory= new OkSSLSocketFactory();
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
builder.followSslRedirects(true)
.retryOnConnectionFailure(true);
builder.sslSocketFactory(new Tls12SocketFactory(okSSLSocketFactory), okSSLSocketFactory.trustManager);
//配置https的域名匹配规则,详细看demo的初始化介绍,不需要就不要加入,使用不当会导致https握手失败
builder.hostnameVerifier(new SafeHostnameVerifier());
ConnectionSpec cs= new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
.tlsVersions(TlsVersion.TLS_1_2)
.build();
List specList= new ArrayList<>();
specList.add(cs);
specList.add(ConnectionSpec.COMPATIBLE_TLS);
specList.add(ConnectionSpec.CLEARTEXT);
Interceptor loggingIntercept= new Interceptor() {
@Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request request= chain.request();
Response response= chain.proceed(request);
ResponseBody responseBody= response.body();
BufferedSource source= responseBody.source();
source.request(Long.MAX_VALUE); // Buffer the entire body.
Buffer buffer= source.buffer();
Charset UTF8= Charset.forName("UTF-8");
Log.w("日志", "intercept: "+buffer.clone().readString(UTF8));
Log.w("日志", "intercept: "+request.toString());
return response;
}
};
builder.addInterceptor(loggingIntercept);
OkHttpClient httpClient= builder.connectionSpecs(specList)
.addInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request= chain.request()//获取请求
.newBuilder()
// .header("Accept-Encoding", "gzip") //header不支持中文,不允许有特殊字符
.header("Accept-Language", "zh-CN,zh;q=0.8")
.header("Accept-Charset", "GBK,utf-8;q=0.7,*;q=0.3")
.addHeader("Connection", "close")
.build();
Log.d("request",request.toString());
return chain.proceed(request);
}
}).build();
return httpClient;
}
//设置Retrofit,不带生命周期绑定的
private Retrofit getRetrofit(){
if (retrofit== null){
if (okHttpClient== null){
okHttpClient= getOkHttpCilent();
}
Gson gson= new GsonBuilder()
.setLenient()
.create();
retrofit= new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create(gson))//json转换器支持
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
}
return retrofit;
}
/**
* 提供方法单独获取okhttpCilent
* @returnokhttpCilent
*/
public OkHttpClient getOkHttpCilent(){
if(okHttpClient== null){
okHttpClient= initOkHttpClient();
}
return okHttpClient;
}
// 主机校验
private class SafeHostnameVerifier implements HostnameVerifier {
@Override
public boolean verify(String hostname, SSLSession session) {
//验证主机名是否匹配
return true;
}
}
// 信任证书
private class OkSSLSocketFactory extends SSLSocketFactory {
SSLContext sslContext= SSLContext.getInstance("TLSv1.2");
public X509TrustManager trustManager;
public OkSSLSocketFactory() throws KeyManagementException, NoSuchAlgorithmException, IOException {
super();
// 使用预埋证书,校验服务端证书(自签名证书)
// TrustManager[] trustManagers = prepareTrustManager(MtsApp.getCtx().getAssets().open("www.major.com.cer"));
// trustManager = chooseTrustManager(trustManagers);
// 信任所有证书
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.init(null, new TrustManager[]{trustManager}, new SecureRandom());
}
@Override
public String[] getDefaultCipherSuites() {
return new String[0];
}
@Override
public String[] getSupportedCipherSuites() {
return new String[0];
}
@Override
public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
return sslContext.getSocketFactory().createSocket(s, host, port, autoClose);
}
@Override
public Socket createSocket(String host, int port) throws IOException {
return sslContext.getSocketFactory().createSocket(host, port);
}
@Override
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
return sslContext.getSocketFactory().createSocket(host, port, localHost, localPort);
}
@Override
public Socket createSocket(InetAddress host, int port) throws IOException {
return sslContext.getSocketFactory().createSocket(host, port);
}
@Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
return sslContext.getSocketFactory().createSocket(address, port, localAddress, localPort);
}
}
// 支持TLSv1.2 ON Android4.x设备的https请求
public class Tls12SocketFactory extends SSLSocketFactory {
private final String[] TLS_V12_ONLY= {"TLSv1.2"};
final SSLSocketFactory delegate;
public Tls12SocketFactory(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, UnknownHostException {
return patch(delegate.createSocket(host, port));
}
@Override
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
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 instanceof SSLSocket) {
((SSLSocket) s).setEnabledProtocols(TLS_V12_ONLY);
}
return s;
}
}
}