pull/32/head
Invinciblelee 6 years ago
parent fe793e5a88
commit 7082209416
  1. 15
      app/src/main/java/io/legado/app/help/http/CoroutinesCallAdapterFactory.kt
  2. 42
      app/src/main/java/io/legado/app/help/http/EncodeConverter.kt
  3. 4914
      app/src/main/java/io/legado/app/help/http/EncodingDetect.java
  4. 23
      app/src/main/java/io/legado/app/help/http/HttpHelper.kt
  5. 92
      app/src/main/java/io/legado/app/help/http/SSLHelper.kt
  6. 3
      app/src/main/java/io/legado/app/ui/search/SearchActivity.kt
  7. 5
      app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt

@ -8,8 +8,9 @@ import java.lang.reflect.Type
class CoroutinesCallAdapterFactory private constructor() : CallAdapter.Factory() {
companion object {
@JvmStatic @JvmName("create")
operator fun invoke() = CoroutinesCallAdapterFactory()
fun create(): CoroutinesCallAdapterFactory {
return CoroutinesCallAdapterFactory()
}
}
override fun get(
@ -22,7 +23,8 @@ class CoroutinesCallAdapterFactory private constructor() : CallAdapter.Factory()
}
if (returnType !is ParameterizedType) {
throw IllegalStateException(
"Deferred return type must be parameterized as Deferred<Foo> or Deferred<out Foo>")
"Deferred return type must be parameterized as Deferred<Foo> or Deferred<out Foo>"
)
}
val responseType = getParameterUpperBound(0, returnType)
@ -30,7 +32,8 @@ class CoroutinesCallAdapterFactory private constructor() : CallAdapter.Factory()
return if (rawDeferredType == Response::class.java) {
if (responseType !is ParameterizedType) {
throw IllegalStateException(
"Response must be parameterized as Response<Foo> or Response<out Foo>")
"Response must be parameterized as Response<Foo> or Response<out Foo>"
)
}
ResponseCallAdapter<Any>(
getParameterUpperBound(
@ -44,7 +47,7 @@ class CoroutinesCallAdapterFactory private constructor() : CallAdapter.Factory()
}
private class BodyCallAdapter<T>(
private val responseType: Type
private val responseType: Type
) : CallAdapter<T, Deferred<T>> {
override fun responseType() = responseType
@ -77,7 +80,7 @@ class CoroutinesCallAdapterFactory private constructor() : CallAdapter.Factory()
}
private class ResponseCallAdapter<T>(
private val responseType: Type
private val responseType: Type
) : CallAdapter<T, Deferred<Response<T>>> {
override fun responseType() = responseType

@ -0,0 +1,42 @@
package io.legado.app.help.http
import okhttp3.ResponseBody
import retrofit2.Converter
import retrofit2.Retrofit
import java.lang.reflect.Type
import java.nio.charset.Charset
class EncodeConverter private constructor(private val encode: String? = null) : Converter.Factory() {
override fun responseBodyConverter(
type: Type?,
annotations: Array<Annotation>?,
retrofit: Retrofit?
): Converter<ResponseBody, String>? {
return Converter { value ->
val responseBytes = value.bytes()
encode?.let { return@Converter String(responseBytes, Charset.forName(encode)) }
var charsetName: String? = null
val mediaType = value.contentType()
//根据http头判断
if (mediaType != null) {
val charset = mediaType.charset()
charsetName = charset?.displayName()
}
if (charsetName == null) {
charsetName = EncodingDetect.getHtmlEncode(responseBytes)
}
String(responseBytes, Charset.forName(charsetName))
}
}
companion object {
fun create(encode: String? = null): EncodeConverter {
return EncodeConverter(encode)
}
}
}

@ -9,17 +9,20 @@ object HttpHelper {
val client: OkHttpClient = getOkHttpClient()
inline fun <reified T> getApiService(baseUrl: String): T {
return getRetrofit(baseUrl).create(T::class.java)
}
fun <T> getApiService(baseUrl: String, clazz: Class<T>): T {
return getRetrofit(baseUrl).create(clazz)
inline fun <reified T> getApiService(baseUrl: String, encode: String): T {
return getRetrofit(baseUrl, encode).create(T::class.java)
}
fun getRetrofit(baseUrl: String): Retrofit {
fun getRetrofit(baseUrl: String, encode: String? = null): Retrofit {
return Retrofit.Builder().baseUrl(baseUrl)
//增加返回值为字符串的支持(以实体类返回)
// .addConverterFactory(EncodeConverter.create())
.addConverterFactory(EncodeConverter.create(encode))
//增加返回值为Observable<T>的支持
.addCallAdapterFactory(CoroutinesCallAdapterFactory.invoke())
.addCallAdapterFactory(CoroutinesCallAdapterFactory.create())
.client(client)
.build()
}
@ -34,20 +37,22 @@ object HttpHelper {
specs.add(ConnectionSpec.COMPATIBLE_TLS)
specs.add(ConnectionSpec.CLEARTEXT)
val sslParams = SSLHelper.getSslSocketFactory()
return OkHttpClient.Builder()
val builder = OkHttpClient.Builder()
.connectTimeout(15, TimeUnit.SECONDS)
.writeTimeout(15, TimeUnit.SECONDS)
.readTimeout(15, TimeUnit.SECONDS)
.retryOnConnectionFailure(true)
.sslSocketFactory(sslParams.sSLSocketFactory, sslParams.trustManager)
.hostnameVerifier(SSLHelper.unsafeHostnameVerifier)
.connectionSpecs(specs)
.followRedirects(true)
.followSslRedirects(true)
.protocols(listOf(Protocol.HTTP_1_1))
.addInterceptor(getHeaderInterceptor())
.build()
SSLHelper.getSslSocketFactory()?.let {
builder.sslSocketFactory(it.sSLSocketFactory, it.trustManager)
}
return builder.build()
}
private fun getHeaderInterceptor(): Interceptor {

@ -1,6 +1,5 @@
package io.legado.app.help.http
import javax.net.ssl.*
import java.io.IOException
import java.io.InputStream
import java.security.KeyManagementException
@ -9,10 +8,11 @@ import java.security.NoSuchAlgorithmException
import java.security.cert.CertificateException
import java.security.cert.CertificateFactory
import java.security.cert.X509Certificate
import javax.net.ssl.*
object SSLHelper {
val sslSocketFactory: SSLParams
val sslSocketFactory: SSLParams?
get() = getSslSocketFactoryBase(null, null, null)
/**
@ -41,15 +41,15 @@ object SSLHelper {
val unsafeHostnameVerifier: HostnameVerifier = HostnameVerifier { _, _ -> true }
class SSLParams {
var sSLSocketFactory: SSLSocketFactory? = null
var trustManager: X509TrustManager? = null
lateinit var sSLSocketFactory: SSLSocketFactory
lateinit var trustManager: X509TrustManager
}
/**
* https单向认证
* 可以额外配置信任服务端的证书策略否则默认是按CA证书去验证的若不是CA可信任的证书则无法通过验证
*/
fun getSslSocketFactory(trustManager: X509TrustManager): SSLParams {
fun getSslSocketFactory(trustManager: X509TrustManager): SSLParams? {
return getSslSocketFactoryBase(trustManager, null, null)
}
@ -57,7 +57,7 @@ object SSLHelper {
* https单向认证
* 用含有服务端公钥的证书校验服务端证书
*/
fun getSslSocketFactory(vararg certificates: InputStream): SSLParams {
fun getSslSocketFactory(vararg certificates: InputStream): SSLParams? {
return getSslSocketFactoryBase(null, null, null, *certificates)
}
@ -66,7 +66,7 @@ object SSLHelper {
* bksFile password -> 客户端使用bks证书校验服务端证书
* certificates -> 用含有服务端公钥的证书校验服务端证书
*/
fun getSslSocketFactory(bksFile: InputStream, password: String, vararg certificates: InputStream): SSLParams {
fun getSslSocketFactory(bksFile: InputStream, password: String, vararg certificates: InputStream): SSLParams? {
return getSslSocketFactoryBase(null, bksFile, password, *certificates)
}
@ -75,7 +75,7 @@ object SSLHelper {
* bksFile password -> 客户端使用bks证书校验服务端证书
* X509TrustManager -> 如果需要自己校验那么可以自己实现相关校验如果不需要自己校验那么传null即可
*/
fun getSslSocketFactory(bksFile: InputStream, password: String, trustManager: X509TrustManager): SSLParams {
fun getSslSocketFactory(bksFile: InputStream, password: String, trustManager: X509TrustManager): SSLParams? {
return getSslSocketFactoryBase(trustManager, bksFile, password)
}
@ -84,35 +84,27 @@ object SSLHelper {
bksFile: InputStream?,
password: String?,
vararg certificates: InputStream
): SSLParams {
): SSLParams? {
val sslParams = SSLParams()
try {
val keyManagers = prepareKeyManager(bksFile, password)
val trustManagers = prepareTrustManager(*certificates)
val manager: X509TrustManager?
manager = //优先使用用户自定义的TrustManager
trustManager ?: if (trustManagers != null) {
//然后使用默认的TrustManager
chooseTrustManager(trustManagers)
} else {
//否则使用不安全的TrustManager
unsafeTrustManager
}
val manager: X509TrustManager = trustManager ?: chooseTrustManager(trustManagers)
// 创建TLS类型的SSLContext对象, that uses our TrustManager
val sslContext = SSLContext.getInstance("TLS")
// 用上面得到的trustManagers初始化SSLContext,这样sslContext就会信任keyStore中的证书
// 第一个参数是授权的密钥管理器,用来授权验证,比如授权自签名的证书验证。第二个是被授权的证书管理器,用来验证服务器端的证书
sslContext.init(keyManagers, manager?.let { arrayOf<TrustManager>(it) }, null)
sslContext.init(keyManagers, arrayOf<TrustManager>(manager), null)
// 通过sslContext获取SSLSocketFactory对象
sslParams.sSLSocketFactory = sslContext.socketFactory
sslParams.trustManager = manager
return sslParams
} catch (e: NoSuchAlgorithmException) {
throw AssertionError(e)
e.printStackTrace()
} catch (e: KeyManagementException) {
throw AssertionError(e)
e.printStackTrace()
}
return null
}
private fun prepareKeyManager(bksFile: InputStream?, password: String?): Array<KeyManager>? {
@ -126,50 +118,40 @@ object SSLHelper {
} catch (e: Exception) {
e.printStackTrace()
}
return null
}
private fun prepareTrustManager(vararg certificates: InputStream): Array<TrustManager>? {
if (certificates.isEmpty()) return null
try {
val certificateFactory = CertificateFactory.getInstance("X.509")
// 创建一个默认类型的KeyStore,存储我们信任的证书
val keyStore = KeyStore.getInstance(KeyStore.getDefaultType())
keyStore.load(null)
var index = 0
for (certStream in certificates) {
val certificateAlias = Integer.toString(index++)
// 证书工厂根据证书文件的流生成证书 cert
val cert = certificateFactory.generateCertificate(certStream)
// 将 cert 作为可信证书放入到keyStore中
keyStore.setCertificateEntry(certificateAlias, cert)
try {
certStream?.close()
} catch (e: IOException) {
e.printStackTrace()
}
private fun prepareTrustManager(vararg certificates: InputStream): Array<TrustManager> {
val certificateFactory = CertificateFactory.getInstance("X.509")
// 创建一个默认类型的KeyStore,存储我们信任的证书
val keyStore = KeyStore.getInstance(KeyStore.getDefaultType())
keyStore.load(null)
for ((index, certStream) in certificates.withIndex()) {
val certificateAlias = Integer.toString(index)
// 证书工厂根据证书文件的流生成证书 cert
val cert = certificateFactory.generateCertificate(certStream)
// 将 cert 作为可信证书放入到keyStore中
keyStore.setCertificateEntry(certificateAlias, cert)
try {
certStream.close()
} catch (e: IOException) {
e.printStackTrace()
}
//我们创建一个默认类型的TrustManagerFactory
val tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
//用我们之前的keyStore实例初始化TrustManagerFactory,这样tmf就会信任keyStore中的证书
tmf.init(keyStore)
//通过tmf获取TrustManager数组,TrustManager也会信任keyStore中的证书
return tmf.trustManagers
} catch (e: Exception) {
e.printStackTrace()
}
return null
//我们创建一个默认类型的TrustManagerFactory
val tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
//用我们之前的keyStore实例初始化TrustManagerFactory,这样tmf就会信任keyStore中的证书
tmf.init(keyStore)
//通过tmf获取TrustManager数组,TrustManager也会信任keyStore中的证书
return tmf.trustManagers
}
private fun chooseTrustManager(trustManagers: Array<TrustManager>): X509TrustManager? {
private fun chooseTrustManager(trustManagers: Array<TrustManager>): X509TrustManager {
for (trustManager in trustManagers) {
if (trustManager is X509TrustManager) {
return trustManager
}
}
return null
throw NullPointerException()
}
}

@ -4,6 +4,7 @@ import android.os.Bundle
import io.legado.app.R
import io.legado.app.base.BaseActivity
import io.legado.app.utils.getViewModel
import org.jetbrains.anko.startActivity
class SearchActivity : BaseActivity<SearchDataBinding, SearchViewModel>() {
@ -14,6 +15,8 @@ class SearchActivity : BaseActivity<SearchDataBinding, SearchViewModel>() {
get() = R.layout.activity_search
override fun onViewModelCreated(viewModel: SearchViewModel, savedInstanceState: Bundle?) {
startActivity<SearchActivity>()
}
}

@ -20,9 +20,8 @@ class SearchViewModel(application: Application) : BaseViewModel(application) {
{
start()
val searchResponse = withContext(IO) {
HttpHelper.getApiService(
"http:www.baidu.com",
CommonHttpApi::class.java
HttpHelper.getApiService<CommonHttpApi>(
"http:www.baidu.com"
).get("", mutableMapOf())
}

Loading…
Cancel
Save