pull/32/head
Invinciblelee 6 years ago
parent fe793e5a88
commit 7082209416
  1. 11
      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. 58
      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() { class CoroutinesCallAdapterFactory private constructor() : CallAdapter.Factory() {
companion object { companion object {
@JvmStatic @JvmName("create") fun create(): CoroutinesCallAdapterFactory {
operator fun invoke() = CoroutinesCallAdapterFactory() return CoroutinesCallAdapterFactory()
}
} }
override fun get( override fun get(
@ -22,7 +23,8 @@ class CoroutinesCallAdapterFactory private constructor() : CallAdapter.Factory()
} }
if (returnType !is ParameterizedType) { if (returnType !is ParameterizedType) {
throw IllegalStateException( 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) val responseType = getParameterUpperBound(0, returnType)
@ -30,7 +32,8 @@ class CoroutinesCallAdapterFactory private constructor() : CallAdapter.Factory()
return if (rawDeferredType == Response::class.java) { return if (rawDeferredType == Response::class.java) {
if (responseType !is ParameterizedType) { if (responseType !is ParameterizedType) {
throw IllegalStateException( 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>( ResponseCallAdapter<Any>(
getParameterUpperBound( getParameterUpperBound(

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

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

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

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

Loading…
Cancel
Save