JetpackMvvm(hegaojian)支持https

JetpackMvvm默認不支持https
JetpackMvvm項目地址:https://github.com/hegaojian/JetpackMvvm

1练对、普通網(wǎng)絡請求添加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
 * 描述 : 網(wǎng)絡請求構建器泄私,繼承BasenetworkApi 并實現(xiàn)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()
        }
    }

    /**
     * 實現(xiàn)重寫父類的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())
                //添加緩存攔截器 可傳入緩存天數(shù)蔚舀,不傳默認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
    }

    /**
     * 實現(xiàn)重寫父類的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疏旨、下載文件網(wǎng)絡請求添加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
    ) {
        //判斷是否已經(jīng)在隊列中
        val scope = DownLoadPool.getScopeFromKey(tag)
        if (scope != null && scope.isActive) {
            "已經(jīng)在隊列中".logi()
            return
        } else if (scope != null && !scope.isActive) {
            "key $tag 已經(jīng)在隊列中 但是已經(jīng)不再活躍 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)
            }
            //調用的下載網(wǎng)絡請求封裝
            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;
    }
}


?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末法挨,一起剝皮案震驚了整個濱河市谁榜,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌凡纳,老刑警劉巖窃植,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異荐糜,居然都是意外死亡巷怜,警方通過查閱死者的電腦和手機葛超,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來延塑,“玉大人绣张,你說我怎么就攤上這事」卮” “怎么了侥涵?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長宋雏。 經(jīng)常有香客問我芜飘,道長,這世上最難降的妖魔是什么磨总? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任嗦明,我火速辦了婚禮,結果婚禮上舍败,老公的妹妹穿的比我還像新娘招狸。我一直安慰自己,他們只是感情好邻薯,可當我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布裙戏。 她就那樣靜靜地躺著,像睡著了一般厕诡。 火紅的嫁衣襯著肌膚如雪累榜。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天灵嫌,我揣著相機與錄音壹罚,去河邊找鬼。 笑死寿羞,一個胖子當著我的面吹牛猖凛,可吹牛的內容都是我干的。 我是一名探鬼主播绪穆,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼辨泳,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了玖院?” 一聲冷哼從身側響起菠红,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎难菌,沒想到半個月后试溯,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡郊酒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年遇绞,在試婚紗的時候發(fā)現(xiàn)自己被綠了键袱。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡试读,死狀恐怖杠纵,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情钩骇,我是刑警寧澤比藻,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站倘屹,受9級特大地震影響银亲,放射性物質發(fā)生泄漏。R本人自食惡果不足惜纽匙,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一务蝠、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧烛缔,春花似錦馏段、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至晕翠,卻和暖如春喷舀,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背淋肾。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工硫麻, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人樊卓。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓拿愧,卻偏偏與公主長得像,于是被迫代替她去往敵國和親碌尔。 傳聞我的和親對象是個殘疾皇子浇辜,可洞房花燭夜當晚...
    茶點故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內容