优化
This commit is contained in:
1 parent
57f696dc06
commit
d3f2ebd538
13 files changed
+60
-22
No files matched your search
@@ -24,7 +24,7 @@ import io.legado.app.help.book.BookHelp
|
||||
import io.legado.app.help.config.AppConfig
|
||||
import io.legado.app.help.config.ThemeConfig.applyDayNight
|
||||
import io.legado.app.help.coroutine.Coroutine
|
||||
import io.legado.app.help.http.cronet.CronetLoader
|
||||
import io.legado.app.help.http.cronet.Cronet
|
||||
import io.legado.app.model.BookCover
|
||||
import io.legado.app.utils.defaultSharedPreferences
|
||||
import io.legado.app.utils.getPrefBoolean
|
||||
@@ -42,7 +42,7 @@ class App : MultiDexApplication() {
|
||||
oldConfig = Configuration(resources.configuration)
|
||||
CrashHandler(this)
|
||||
//预下载Cronet so
|
||||
CronetLoader.preDownload()
|
||||
Cronet.preDownload()
|
||||
createNotificationChannels()
|
||||
applyDayNight(this)
|
||||
LiveEventBus.config()
|
||||
|
||||
@@ -3,8 +3,7 @@ package io.legado.app.help.http
|
||||
import io.legado.app.constant.AppConst
|
||||
import io.legado.app.help.CacheManager
|
||||
import io.legado.app.help.config.AppConfig
|
||||
import io.legado.app.help.http.cronet.CronetInterceptor
|
||||
import io.legado.app.help.http.cronet.CronetLoader
|
||||
import io.legado.app.help.http.cronet.Cronet
|
||||
import io.legado.app.utils.NetworkUtils
|
||||
import okhttp3.*
|
||||
import java.net.InetSocketAddress
|
||||
@@ -70,8 +69,12 @@ val okHttpClient: OkHttpClient by lazy {
|
||||
builder.addHeader("Cache-Control", "no-cache")
|
||||
chain.proceed(builder.build())
|
||||
})
|
||||
if (!AppConfig.isGooglePlay && AppConfig.isCronet && CronetLoader.install()) {
|
||||
builder.addInterceptor(CronetInterceptor(cookieJar = cookieJar))
|
||||
if (!AppConfig.isGooglePlay && AppConfig.isCronet) {
|
||||
if (Cronet.loader?.install() == true) {
|
||||
Cronet.interceptor?.let {
|
||||
builder.addInterceptor(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
builder.build()
|
||||
}
|
||||
|
||||
@@ -1,232 +0,0 @@
|
||||
package io.legado.app.help.http.cronet
|
||||
|
||||
import io.legado.app.help.http.okHttpClient
|
||||
import io.legado.app.utils.DebugLog
|
||||
import io.legado.app.utils.asIOException
|
||||
import okhttp3.*
|
||||
import okhttp3.EventListener
|
||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||
import okhttp3.ResponseBody.Companion.asResponseBody
|
||||
import okio.Buffer
|
||||
import org.chromium.net.CronetException
|
||||
import org.chromium.net.UrlRequest
|
||||
import org.chromium.net.UrlResponseInfo
|
||||
import java.io.IOException
|
||||
import java.nio.ByteBuffer
|
||||
import java.util.*
|
||||
|
||||
abstract class AbsCallBack(
|
||||
val originalRequest: Request,
|
||||
val mCall: Call,
|
||||
private val eventListener: EventListener? = null,
|
||||
private val responseCallback: Callback? = null
|
||||
|
||||
) : UrlRequest.Callback(), AutoCloseable {
|
||||
|
||||
val buffer = Buffer()
|
||||
|
||||
var mResponse: Response
|
||||
|
||||
private var followCount = 0
|
||||
|
||||
|
||||
@Throws(IOException::class)
|
||||
abstract fun waitForDone(urlRequest: UrlRequest): Response
|
||||
|
||||
/**
|
||||
* 当发生错误时,通知子类终止阻塞抛出错误
|
||||
* @param error
|
||||
*/
|
||||
abstract fun onError(error: IOException)
|
||||
|
||||
/**
|
||||
* 请求成功后,通知子类结束阻塞,返回response
|
||||
* @param response
|
||||
*/
|
||||
abstract fun onSuccess(response: Response)
|
||||
|
||||
|
||||
override fun onRedirectReceived(
|
||||
request: UrlRequest,
|
||||
info: UrlResponseInfo,
|
||||
newLocationUrl: String
|
||||
) {
|
||||
if (followCount > MAX_FOLLOW_COUNT) {
|
||||
request.cancel()
|
||||
onError(IOException("Too many redirect"))
|
||||
return
|
||||
}
|
||||
if (mCall.isCanceled()) {
|
||||
onError(IOException("Request Canceled"))
|
||||
request.cancel()
|
||||
return
|
||||
}
|
||||
followCount += 1
|
||||
val client = okHttpClient
|
||||
if (originalRequest.url.isHttps && newLocationUrl.startsWith("http://") && client.followSslRedirects) {
|
||||
request.followRedirect()
|
||||
} else if (!originalRequest.url.isHttps && newLocationUrl.startsWith("https://") && client.followSslRedirects) {
|
||||
request.followRedirect()
|
||||
} else if (okHttpClient.followRedirects) {
|
||||
request.followRedirect()
|
||||
} else {
|
||||
onError(IOException("Too many redirect"))
|
||||
request.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun onResponseStarted(request: UrlRequest, info: UrlResponseInfo) {
|
||||
this.mResponse = responseFromResponse(this.mResponse, info)
|
||||
//打印协议,用于调试
|
||||
DebugLog.i(javaClass.simpleName, "start[${info.negotiatedProtocol}]${info.url}")
|
||||
if (eventListener != null) {
|
||||
eventListener.responseHeadersEnd(mCall, this.mResponse)
|
||||
eventListener.responseBodyStart(mCall)
|
||||
}
|
||||
request.read(ByteBuffer.allocateDirect(32 * 1024))
|
||||
}
|
||||
|
||||
|
||||
@Throws(IOException::class)
|
||||
override fun onReadCompleted(
|
||||
request: UrlRequest,
|
||||
info: UrlResponseInfo,
|
||||
byteBuffer: ByteBuffer
|
||||
) {
|
||||
|
||||
|
||||
if (mCall.isCanceled()) {
|
||||
request.cancel()
|
||||
onError(IOException("Request Canceled"))
|
||||
}
|
||||
|
||||
byteBuffer.flip()
|
||||
|
||||
try {
|
||||
buffer.write(byteBuffer)
|
||||
} catch (e: IOException) {
|
||||
DebugLog.e(javaClass.name, "IOException during ByteBuffer read. Details: ", e)
|
||||
onError(IOException("IOException during ByteBuffer read. Details:", e))
|
||||
return
|
||||
}
|
||||
byteBuffer.clear()
|
||||
request.read(byteBuffer)
|
||||
}
|
||||
|
||||
|
||||
override fun onSucceeded(request: UrlRequest, info: UrlResponseInfo) {
|
||||
eventListener?.responseBodyEnd(mCall, info.receivedByteCount)
|
||||
val contentType: MediaType? = (this.mResponse.header("content-type")
|
||||
?: "text/plain; charset=\"utf-8\"").toMediaTypeOrNull()
|
||||
val responseBody: ResponseBody =
|
||||
buffer.asResponseBody(contentType)
|
||||
val newRequest = originalRequest.newBuilder().url(info.url).build()
|
||||
this.mResponse = this.mResponse.newBuilder().body(responseBody).request(newRequest).build()
|
||||
onSuccess(this.mResponse)
|
||||
//DebugLog.i(javaClass.simpleName, "end[${info.negotiatedProtocol}]${info.url}")
|
||||
|
||||
eventListener?.callEnd(mCall)
|
||||
if (responseCallback != null) {
|
||||
try {
|
||||
responseCallback.onResponse(mCall, this.mResponse)
|
||||
} catch (e: IOException) {
|
||||
// Pass?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//UrlResponseInfo可能为null
|
||||
override fun onFailed(request: UrlRequest, info: UrlResponseInfo?, error: CronetException) {
|
||||
DebugLog.e(javaClass.name, error.message.toString())
|
||||
onError(error.asIOException())
|
||||
this.eventListener?.callFailed(mCall, error)
|
||||
responseCallback?.onFailure(mCall, error)
|
||||
}
|
||||
|
||||
override fun onCanceled(request: UrlRequest?, info: UrlResponseInfo?) {
|
||||
super.onCanceled(request, info)
|
||||
this.eventListener?.callEnd(mCall)
|
||||
//onError(IOException("Cronet Request Canceled"))
|
||||
}
|
||||
|
||||
|
||||
init {
|
||||
mResponse = Response.Builder()
|
||||
.sentRequestAtMillis(System.currentTimeMillis())
|
||||
.request(originalRequest)
|
||||
.protocol(Protocol.HTTP_1_0)
|
||||
.code(0)
|
||||
.message("")
|
||||
.build()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val MAX_FOLLOW_COUNT = 20
|
||||
private fun protocolFromNegotiatedProtocol(responseInfo: UrlResponseInfo): Protocol {
|
||||
val negotiatedProtocol = responseInfo.negotiatedProtocol.lowercase(Locale.getDefault())
|
||||
return when {
|
||||
negotiatedProtocol.contains("h3") -> {
|
||||
return Protocol.QUIC
|
||||
}
|
||||
negotiatedProtocol.contains("quic") -> {
|
||||
Protocol.QUIC
|
||||
}
|
||||
negotiatedProtocol.contains("spdy") -> {
|
||||
@Suppress("DEPRECATION")
|
||||
Protocol.SPDY_3
|
||||
}
|
||||
negotiatedProtocol.contains("h2") -> {
|
||||
Protocol.HTTP_2
|
||||
}
|
||||
negotiatedProtocol.contains("1.1") -> {
|
||||
Protocol.HTTP_1_1
|
||||
}
|
||||
else -> {
|
||||
Protocol.HTTP_1_0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun headersFromResponse(responseInfo: UrlResponseInfo): Headers {
|
||||
val headers = responseInfo.allHeadersAsList
|
||||
return Headers.Builder().apply {
|
||||
for ((key, value) in headers) {
|
||||
try {
|
||||
|
||||
if (key.equals("content-encoding", ignoreCase = true)) {
|
||||
// Strip all content encoding headers as decoding is done handled by cronet
|
||||
continue
|
||||
}
|
||||
add(key, value)
|
||||
} catch (e: Exception) {
|
||||
DebugLog.w(javaClass.name, "Invalid HTTP header/value: $key$value")
|
||||
// Ignore that header
|
||||
}
|
||||
}
|
||||
|
||||
}.build()
|
||||
|
||||
}
|
||||
|
||||
private fun responseFromResponse(
|
||||
response: Response,
|
||||
responseInfo: UrlResponseInfo
|
||||
): Response {
|
||||
val protocol = protocolFromNegotiatedProtocol(responseInfo)
|
||||
val headers = headersFromResponse(responseInfo)
|
||||
return response.newBuilder()
|
||||
.receivedResponseAtMillis(System.currentTimeMillis())
|
||||
.protocol(protocol)
|
||||
.code(responseInfo.httpStatusCode)
|
||||
.message(responseInfo.httpStatusText)
|
||||
.headers(headers)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
buffer.clear()
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
package io.legado.app.help.http.cronet
|
||||
|
||||
import okhttp3.RequestBody
|
||||
import okio.Buffer
|
||||
import org.chromium.net.UploadDataProvider
|
||||
import org.chromium.net.UploadDataSink
|
||||