美文网首页
JetpackMvvm(hegaojian)支持https

JetpackMvvm(hegaojian)支持https

作者: 因为我的心 | 来源:发表于2024-05-10 13:12 被阅读0次

    JetpackMvvm默认不支持https
    JetpackMvvm项目地址:https://github.com/hegaojian/JetpackMvvm

    1、普通网络请求添加SSL:

    package com.asura.android.tmspda.base.network
    
    import com.asura.android.tmspda.common.BaseConfig
    import com.google.gson.GsonBuilder
    import me.hgj.jetpackmvvm.base.appContext
    import me.hgj.jetpackmvvm.ext.ssl.SSLSocketClient2
    import me.hgj.jetpackmvvm.network.BaseNetworkApi
    import me.hgj.jetpackmvvm.network.interceptor.CacheInterceptor
    import me.hgj.jetpackmvvm.network.interceptor.logging.LogInterceptor
    import me.hgj.jetpackmvvm.util.LogUtils
    import okhttp3.Cache
    import okhttp3.OkHttpClient
    import retrofit2.Retrofit
    import retrofit2.converter.gson.GsonConverterFactory
    import java.io.File
    import java.util.concurrent.TimeUnit
    
    /**
     * 作者 : hegaojian
     * 时间 : 2019/12/23
     * 描述 : 网络请求构建器,继承BasenetworkApi 并实现setHttpClientBuilder/setRetrofitBuilder方法,
     * 在这里可以添加拦截器,设置构造器可以对Builder做任意操作
     */
    
    
    /**
     * 域名1:双重校验锁式-单例 封装NetApiService 方便直接快速调用简单的接口
     */
    val apiService: ApiService by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
        NetworkApi.INSTANCE.getApi(ApiService::class.java, BaseConfig.getBaseurl())
    }
    
    /**
     * 域名2:双重校验锁式-单例 封装NetApiService 方便直接快速调用简单的接口
     */
    val apiService2: ApiService by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
        NetworkApi.INSTANCE.getApi(ApiService::class.java, BaseConfig.getBaseUrl2())
    }
    
    
    class NetworkApi : BaseNetworkApi() {
        companion object {
            val INSTANCE: NetworkApi by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
                NetworkApi()
            }
        }
    
        /**
         * 实现重写父类的setHttpClientBuilder方法,
         * 在这里可以添加拦截器,可以对 OkHttpClient.Builder 做任意操作
         */
        override fun setHttpClientBuilder(builder: OkHttpClient.Builder): OkHttpClient.Builder {
            try {
                builder.apply {
                    //设置缓存配置 缓存最大10M
                    cache(Cache(File(appContext.cacheDir, "cxk_cache"), 10 * 1024 * 1024))
                    //添加Cookies自动持久化
                    //  cookieJar(cookieJar)
                    //示例:添加公共heads 注意要设置在日志拦截器之前,不然Log中会不显示head信息
                    addInterceptor(MyHeadInterceptor())
                    //添加缓存拦截器 可传入缓存天数,不传默认7天
                    addInterceptor(CacheInterceptor())
                    addInterceptor(TokenOutInterceptor())
                    // 日志拦截器
                    addInterceptor(LogInterceptor())
    
                    //1、SSL配置一
    //              .sslSocketFactory(SSLSocketClient.getSSLSocketFactory(), SSLSocketClient.geX509tTrustManager())
    //              .hostnameVerifier(SSLSocketClient.getHostnameVerifier());
                    //2、SSL配置一
                    .sslSocketFactory(SSLSocketClient2.getSSLSocketFactory())//配置
                    .hostnameVerifier(SSLSocketClient2.getHostnameVerifier())//配置
                    //超时时间 连接、读、写
                    connectTimeout(30, TimeUnit.SECONDS)
                    readTimeout(30, TimeUnit.SECONDS)
                    writeTimeout(30, TimeUnit.SECONDS)
    
                }
            } catch (e: Exception) {
            }
            return builder
        }
    
        /**
         * 实现重写父类的setRetrofitBuilder方法,
         * 在这里可以对Retrofit.Builder做任意操作,比如添加GSON解析器,protobuf等
         */
        override fun setRetrofitBuilder(builder: Retrofit.Builder): Retrofit.Builder {
            return builder.apply {
                addConverterFactory(GsonConverterFactory.create(GsonBuilder().create()))
            }
        }
    
    //    val cookieJar: PersistentCookieJar by lazy {
    //        PersistentCookieJar(SetCookieCache(), SharedPrefsCookiePersistor(appContext))
    //    }
    
    }
    

    2、下载文件网络请求添加SSL:

    package me.hgj.jetpackmvvm.ext.download
    
    import android.os.Looper
    import kotlinx.coroutines.CoroutineScope
    import kotlinx.coroutines.Dispatchers
    import kotlinx.coroutines.isActive
    import kotlinx.coroutines.withContext
    import me.hgj.jetpackmvvm.ext.ssl.SSLSocketClient
    import me.hgj.jetpackmvvm.ext.ssl.SSLSocketClient2
    import me.hgj.jetpackmvvm.ext.util.logi
    import okhttp3.OkHttpClient
    import retrofit2.Retrofit
    import java.io.File
    import java.util.concurrent.TimeUnit
    
    /**
     * @author : hgj
     * @date   : 2020/7/13
     */
    
    object DownLoadManager {
        private val retrofitBuilder by lazy {
            Retrofit.Builder()
                .baseUrl("https://www.baidu.com")
                .client(
                    OkHttpClient.Builder()
                        //1、SSL配置一
    //                    .sslSocketFactory(SSLSocketClient.getSSLSocketFactory(), SSLSocketClient.geX509tTrustManager())
    //                    .hostnameVerifier(SSLSocketClient.getHostnameVerifier())
                        //2、SSL配置一
                      .sslSocketFactory(SSLSocketClient2.getSSLSocketFactory())//配置
                      .hostnameVerifier(SSLSocketClient2.getHostnameVerifier())//配置
    
                        .connectTimeout(10, TimeUnit.SECONDS)
                        .readTimeout(5, TimeUnit.SECONDS)
                        .writeTimeout(5, TimeUnit.SECONDS).build()
                ).build()
        }
    
        /**
         *开始下载
         * @param tag String 标识
         * @param url String  下载的url
         * @param savePath String 保存的路径
         * @param saveName String 保存的名字
         * @param reDownload Boolean 如果文件已存在是否需要重新下载 默认不需要重新下载
         * @param loadListener OnDownLoadListener
         */
        suspend fun downLoad(
            tag: String,
            url: String,
            savePath: String,
            saveName: String,
            reDownload: Boolean = false,
            loadListener: OnDownLoadListener
        ) {
            withContext(Dispatchers.IO) {
                doDownLoad(tag, url, savePath, saveName, reDownload, loadListener, this)
            }
        }
    
        /**
         * 取消下载
         * @param key String 取消的标识
         */
        fun cancel(key: String) {
            val path = DownLoadPool.getPathFromKey(key)
            if (path != null) {
                val file = File(path)
                if (file.exists()) {
                    file.delete()
                }
            }
            DownLoadPool.remove(key)
        }
    
        /**
         * 暂停下载
         * @param key String 暂停的标识
         */
        fun pause(key: String) {
            val listener = DownLoadPool.getListenerFromKey(key)
            listener?.onDownLoadPause(key)
            DownLoadPool.pause(key)
        }
    
        /**
         * 取消所有下载
         */
        fun doDownLoadCancelAll() {
            DownLoadPool.getListenerMap().forEach {
                cancel(it.key)
            }
        }
    
        /**
         * 暂停所有下载
         */
        fun doDownLoadPauseAll() {
            DownLoadPool.getListenerMap().forEach {
                pause(it.key)
            }
        }
    
        /**
         *下载
         * @param tag String 标识
         * @param url String  下载的url
         * @param savePath String 保存的路径
         * @param saveName String 保存的名字
         * @param reDownload Boolean 如果文件已存在是否需要重新下载 默认不需要重新下载
         * @param loadListener OnDownLoadListener
         * @param coroutineScope CoroutineScope 上下文
         */
        private suspend fun doDownLoad(
            tag: String,
            url: String,
            savePath: String,
            saveName: String,
            reDownload: Boolean,
            loadListener: OnDownLoadListener,
            coroutineScope: CoroutineScope
        ) {
            //判断是否已经在队列中
            val scope = DownLoadPool.getScopeFromKey(tag)
            if (scope != null && scope.isActive) {
                "已经在队列中".logi()
                return
            } else if (scope != null && !scope.isActive) {
                "key $tag 已经在队列中 但是已经不再活跃 remove".logi()
                DownLoadPool.removeExitSp(tag)
            }
    
            if (saveName.isEmpty()) {
                withContext(Dispatchers.Main) {
                    loadListener.onDownLoadError(tag, Throwable("save name is Empty"))
                }
                return
            }
    
            if (Looper.getMainLooper().thread == Thread.currentThread()) {
                withContext(Dispatchers.Main) {
                    loadListener.onDownLoadError(tag, Throwable("current thread is in main thread"))
                }
                return
            }
    
            val file = File("$savePath/$saveName")
            val currentLength = if (!file.exists()) {
                0L
            } else {
                ShareDownLoadUtil.getLong(tag, 0)
            }
            if (file.exists() && currentLength == 0L && !reDownload) {
                //文件已存在了
                loadListener.onDownLoadSuccess(tag, file.path, file.length())
                return
            }
            "startDownLoad current $currentLength".logi()
    
            try {
                //添加到pool
                DownLoadPool.add(tag, coroutineScope)
                DownLoadPool.add(tag, "$savePath/$saveName")
                DownLoadPool.add(tag, loadListener)
    
                withContext(Dispatchers.Main) {
                    loadListener.onDownLoadPrepare(key = tag)
                }
                //调用的下载网络请求封装
                val response = retrofitBuilder.create(DownLoadService::class.java)
                    .downloadFile("bytes=$currentLength-", url)
                val responseBody = response.body()
                if (responseBody == null) {
                    "responseBody is null".logi()
                    withContext(Dispatchers.Main) {
                        loadListener.onDownLoadError(
                            key = tag,
                            throwable = Throwable("responseBody is null please check download url")
                        )
                    }
                    DownLoadPool.remove(tag)
                    return
                }
                FileTool.downToFile(
                    tag,
                    savePath,
                    saveName,
                    currentLength,
                    responseBody,
                    loadListener
                )
            } catch (throwable: Throwable) {
                withContext(Dispatchers.Main) {
                    loadListener.onDownLoadError(key = tag, throwable = throwable)
                }
                DownLoadPool.remove(tag)
            }
        }
    }
    
    

    3、配置SSLSocketClient

    package com.example.myapplication.utils;
    
    import java.security.SecureRandom;
    import java.security.cert.X509Certificate;
    
    import javax.net.ssl.HostnameVerifier;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.SSLSession;
    import javax.net.ssl.SSLSocketFactory;
    import javax.net.ssl.TrustManager;
    import javax.net.ssl.X509TrustManager;
    
    /**
     * @author lyy
     * 方案一:让okhttp支持https请求
     */
    public class SSLSocketClient {
    
        public static SSLSocketFactory getSSLSocketFactory() {
            try {
                SSLContext sslContext = SSLContext.getInstance("SSL");
                sslContext.init(null, getTrustManager(), new SecureRandom());
                return sslContext.getSocketFactory();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    
        private static TrustManager[] getTrustManager() {
            return new TrustManager[]{
                    new X509TrustManager() {
                        @Override
                        public void checkClientTrusted(X509Certificate[] chain, String authType) {
                        }
    
                        @Override
                        public void checkServerTrusted(X509Certificate[] chain, String authType) {
                        }
    
                        @Override
                        public X509Certificate[] getAcceptedIssuers() {
                            return new X509Certificate[]{};
                        }
                    }
            };
        }
    
        public static X509TrustManager geX509tTrustManager() {
            return new X509TrustManager() {
                @Override
                public void checkClientTrusted(X509Certificate[] chain, String authType) {
                }
    
                @Override
                public void checkServerTrusted(X509Certificate[] chain, String authType) {
                }
    
                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return new X509Certificate[]{};
                }
            };
        }
    
        public static HostnameVerifier getHostnameVerifier() {
            return new HostnameVerifier() {
                @Override
                public boolean verify(String s, SSLSession sslSession) {
                    return true;
                }
            };
        }
    }
    

    4、配置SSLSocketClient2

    package com.example.myapplication.utils;
    
    import java.security.SecureRandom;
    import java.security.cert.X509Certificate;
    
    import javax.net.ssl.HostnameVerifier;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.SSLSession;
    import javax.net.ssl.SSLSocketFactory;
    import javax.net.ssl.TrustManager;
    import javax.net.ssl.X509TrustManager;
    /**
     * @author lyy
     * 方案二:让okhttp支持https请求
     */
    public class SSLSocketClient2 {
        //获取这个SSLSocketFactory
        public static SSLSocketFactory getSSLSocketFactory() {
            try {
                SSLContext sslContext = SSLContext.getInstance("SSL");
                sslContext.init(null, getTrustManager(), new SecureRandom());
                return sslContext.getSocketFactory();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    
        //获取TrustManager
        private static TrustManager[] getTrustManager() {
            TrustManager[] trustAllCerts = new TrustManager[]{
                    new X509TrustManager() {
                        @Override
                        public void checkClientTrusted(X509Certificate[] chain, String authType) {
                        }
    
                        @Override
                        public void checkServerTrusted(X509Certificate[] chain, String authType) {
                        }
    
                        @Override
                        public X509Certificate[] getAcceptedIssuers() {
                            return new X509Certificate[]{};
                        }
                    }
            };
            return trustAllCerts;
        }
    
        //获取HostnameVerifier
        public static HostnameVerifier getHostnameVerifier() {
            HostnameVerifier hostnameVerifier = new HostnameVerifier() {
                @Override
                public boolean verify(String s, SSLSession sslSession) {
                    return true;
                }
            };
            return hostnameVerifier;
        }
    }
    
    
    

    相关文章

      网友评论

          本文标题:JetpackMvvm(hegaojian)支持https

          本文链接:https://www.haomeiwen.com/subject/sdcefjtx.html