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;
}
}
网友评论