OKHTTP 默认构建包含 android 4.4 的TLS 1.2 以及设备时间不对兼容

kotlin

Kotlin 复制代码
import android.annotation.SuppressLint
import android.os.Build
import java.net.Proxy
import java.security.KeyStore
import java.security.SecureRandom
import java.security.cert.CertPathValidatorException
import java.security.cert.CertificateException
import java.security.cert.CertificateExpiredException
import java.security.cert.CertificateNotYetValidException
import java.security.cert.X509Certificate
import java.util.concurrent.TimeUnit
import javax.net.ssl.SSLContext
import javax.net.ssl.SSLSocketFactory
import javax.net.ssl.TrustManager
import javax.net.ssl.TrustManagerFactory
import javax.net.ssl.X509TrustManager
import okhttp3.OkHttpClient
import okhttp3.Request

/**
 * <pre>
 * desc   : 用于统一创建okhttp
</pre> *
 */
object DefOkHttp {
    /**
     * 获取默认的OKhttp实例
     * @return
     * 默认的全局okhttp类
     */
    @JvmStatic
    val default: OkHttpClient = newOkHttpClient(OkHttpClient.Builder())

    @JvmStatic
    val defaultHeaders = hashMapOf<String, String>()

    init {
        defaultHeaders["x-brand"] = checkHeaderValue(Build.MODEL, "unknown")
        defaultHeaders["x-platform"] = "android" + Build.VERSION.SDK_INT
    }

    /**
     * 由于okhttp header不容许携带中文,故
     */
    private fun checkHeaderValue(value: String?, defaultVal: String): String {
        if (value == null) {
            return defaultVal
        } else {
            for (c in value) {
                if (c.code <= 31 && c != '\t' || c.code >= 127) {
                    return defaultVal
                }
            }
            return value
        }
    }

    @Synchronized
    @JvmStatic
    fun addDefaultHeader(key: String, value: String) {
        defaultHeaders[key] = value
    }

    /**
     * 创建一个新的okHttp实例
     * @param builder
     * okhttp构建者
     * @return
     * okhttp实例
     */
    @Synchronized
    @JvmStatic
    fun newOkHttpClient(builder: OkHttpClient.Builder): OkHttpClient {
        return patchDefaultBuilder(builder).build()
    }

    /**
     * 创建一个默认的builder类
     * @return
     * 默认的okhttp builder类
     */
    @Synchronized
    @JvmStatic
    fun newDefaultBuilder(): OkHttpClient.Builder {
        return patchDefaultBuilder(OkHttpClient.Builder())
    }

    /**
     * 增加默认配置
     * @param builder:外部构建者
     */
    @JvmStatic
    private fun patchDefaultBuilder(builder: OkHttpClient.Builder): OkHttpClient.Builder {
        patchSSL(builder)
        builder.proxy(Proxy.NO_PROXY)

        // 增加固定header
        builder.addInterceptor { chain ->
            val originalRequest: Request = chain.request()

            // 使用newBuilder复制原始请求
            val newRequestBuilder: Request.Builder = originalRequest.newBuilder()

            // 添加固定的header头部
            for ((key, value) in defaultHeaders) {
                newRequestBuilder.addHeader(key, value)
            }

            // 构建新的请求
            val newRequest: Request = newRequestBuilder.build()

            // 继续处理请求
            chain.proceed(newRequest)
        }

        return builder
    }

    @Suppress("CAST_NEVER_SUCCEEDS")
    private fun patchSSL(builder: OkHttpClient.Builder): OkHttpClient.Builder {
        try {
            val tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm()
            val tmf = TrustManagerFactory.getInstance(tmfAlgorithm)
            val socketFactory: SSLSocketFactory
            tmf.init(null as? KeyStore)
            val sslContext = SSLContext.getInstance("TLS")
            val trustManagers = tmf.trustManagers
            val x509TrustManager = trustManagers[0] as X509TrustManager
            sslContext.init(null, getWrappedTrustManagers(trustManagers), SecureRandom())
            socketFactory = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT_WATCH) {
                val socketFactoryNoTls = sslContext.socketFactory
                TLS12SocketFactory(socketFactoryNoTls)
            } else {
                sslContext.socketFactory
            }
            builder.connectTimeout(8, TimeUnit.SECONDS)
                .readTimeout(8, TimeUnit.SECONDS)
                .writeTimeout(8, TimeUnit.SECONDS)
                .sslSocketFactory(socketFactory, x509TrustManager)
                .followRedirects(true)
                .followSslRedirects(true)
                .retryOnConnectionFailure(true)
                .build()
        } catch (_: Exception) {
            builder.connectTimeout(8, TimeUnit.SECONDS)
                .readTimeout(8, TimeUnit.SECONDS)
                .writeTimeout(8, TimeUnit.SECONDS)
                .followRedirects(true)
                .followSslRedirects(true)
                .retryOnConnectionFailure(true)
        }

        return builder
    }

    @SuppressLint("CustomX509TrustManager")
    private fun getWrappedTrustManagers(trustManagers: Array<TrustManager>): Array<TrustManager> {
        val originalTrustManager = trustManagers[0] as X509TrustManager
        return arrayOf(
            object : X509TrustManager {
                override fun getAcceptedIssuers(): Array<X509Certificate> {
                    return originalTrustManager.acceptedIssuers
                }

                @Throws(CertificateException::class)
                override fun checkClientTrusted(certs: Array<X509Certificate>, authType: String) {
                    try {
                        originalTrustManager.checkClientTrusted(certs, authType)
                    } catch (e: CertificateException) {
                        if (e.cause is CertificateNotYetValidException ||
                            e.cause?.cause is CertificateNotYetValidException ||
                            e.cause is CertPathValidatorException ||
                            e.cause ?.cause is CertPathValidatorException ||
                            e.cause is CertificateExpiredException ||
                            e.cause ?.cause is CertificateExpiredException
                        ) {
                            Log.d("checkClientTrusted post CertificateNotYetValidEvent----")
                        } else {
                            throw e
                        }
                    }
                }

                @Throws(CertificateException::class)
                override fun checkServerTrusted(certs: Array<X509Certificate>, authType: String) {
                    try {
                        originalTrustManager.checkServerTrusted(certs, authType)
                    } catch (e: CertificateException) {
                        if (e.cause is CertificateNotYetValidException ||
                            e.cause?.cause is CertificateNotYetValidException ||
                            e.cause is CertPathValidatorException ||
                            e.cause ?.cause is CertPathValidatorException ||
                            e.cause is CertificateExpiredException ||
                            e.cause ?.cause is CertificateExpiredException
                        ) {
                            Log.d("checkServerTrusted post CertificateNotYetValidEvent----")
                        } else {
                            throw e
                        }
                    }
                }
            })
    }
}

使用:

Kotlin 复制代码
DefOkHttp.newDefaultBuilder()

旧版JAVA

java 复制代码
import android.os.Build;
import android.util.Log;


import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.cert.CertPathValidatorException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateNotYetValidException;
import java.security.cert.X509Certificate;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

public class CertImpl {

    public long getTimeInMs() {
        return System.currentTimeMillis();
    }

    public SSLSocketFactory getCertImpl() {
        try {
            SSLSocketFactory socketFactory = null;

            String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
            tmf.init((KeyStore) null);
            SSLContext sslContext = SSLContext.getInstance("TLS");
            TrustManager[] trustManagers = tmf.getTrustManagers();
            sslContext.init(null, getWrappedTrustManagers(trustManagers), new SecureRandom());
            if(Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT_WATCH){
                socketFactory = new Tls12SocketFactory(sslContext.getSocketFactory());
            }else{
                socketFactory = sslContext.getSocketFactory();
            }
            return socketFactory;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private static TrustManager[] getWrappedTrustManagers(TrustManager[] trustManagers) {
        final X509TrustManager originalTrustManager = (X509TrustManager) trustManagers[0];
        return new TrustManager[]{ new X509TrustManager() {
            public X509Certificate[] getAcceptedIssuers() {
                return originalTrustManager.getAcceptedIssuers();
            }

            public void checkClientTrusted(X509Certificate[] certs, String authType) throws CertificateException {
                try {
                    originalTrustManager.checkClientTrusted(certs, authType);
                } catch (CertificateException e) {
                    if (e.getCause() instanceof CertificateNotYetValidException
                            || (e.getCause() != null && e.getCause().getCause() instanceof CertificateNotYetValidException)
                            || (e.getCause() instanceof CertPathValidatorException)
                            || e.getCause() instanceof CertificateExpiredException
                            || (e.getCause() != null && e.getCause().getCause() instanceof CertificateExpiredException)) {
                        Log.i("checkServerTrusted post CertificateNotYetValidEvent----");
                    } else {
                        throw e;
                    }
                }
            }

            public void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException {
                try {
                    originalTrustManager.checkServerTrusted(certs, authType);
                } catch (CertificateException e) {
                    if (e.getCause() instanceof CertificateNotYetValidException
                            || (e.getCause() != null && e.getCause().getCause() instanceof CertificateNotYetValidException)
                            || (e.getCause() instanceof CertPathValidatorException)
                            || e.getCause() instanceof CertificateExpiredException
                            || (e.getCause() != null && e.getCause().getCause() instanceof CertificateExpiredException)) {
                        Log.d("CertImpl", "checkServerTrusted post CertificateNotYetValidEvent--");
                    } else {
                        throw e;
                    }
                }
            }
        }};
    }

}

使用:

java 复制代码
    public static OkHttpClient getClient() {
        if (mOkHttpClient == null) {
            okhttp3.OkHttpClient.Builder clientBuilder = getBuilder();
            try {
                SSLSocketFactory factory = new CertImpl().getCertImpl();
                clientBuilder.sslSocketFactory(factory);
            }catch (Exception e){
                e.printStackTrace();
            }
            mOkHttpClient = clientBuilder.build();
        }
        return mOkHttpClient;
    }
相关推荐
云起SAAS5 小时前
抖音小游戏源码 - 消消乐 | 含激励广告+成就系统 | 开箱即用商业级消除游戏模板
android·游戏·广告联盟·看激励广告联盟流量主·抖音小游戏源码 - 消消乐
大貔貅喝啤酒7 小时前
基于Windows下载安装Android Studio 3.3.2版本教程(2026详细图文版)
android·java·windows·android studio
程序员码歌7 小时前
OpenSpec 到 Superpowers:AI 编码从说清到做对
android·前端·人工智能
2501_915106327 小时前
深入解析无源码iOS加固原理与方案,保护应用安全
android·安全·ios·小程序·uni-app·cocoa·iphone
hj10439 小时前
fastadmin 开发示例:使用 layer 弹窗实现数据快速录入
okhttp
黄林晴11 小时前
重磅官宣:Android UI 开发正式进入 Compose-first 时代
android·google io
Kapaseker11 小时前
搞懂变换!精通 Compose 绘制(二)
android·kotlin
美狐美颜SDK开放平台11 小时前
美颜SDK开发详解:如何优化美颜SDK在低端安卓机上的性能?
android·ios·音视频·直播美颜sdk·视频美颜sdk
Gary Studio11 小时前
深入MTK Android BSP:如何确定编译目标与查找项目设备树
android
casual_clover11 小时前
【Android】实现状态栏背景透明,系统时间/图标直接显示在页面背景上
android·透明状态栏