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;
}
}