diff --git a/app/src/main/java/io/legado/app/help/http/cronet/AbsCallBack.kt b/app/src/main/java/io/legado/app/help/http/cronet/AbsCallBack.kt index 192206435..7d7ba8cb7 100644 --- a/app/src/main/java/io/legado/app/help/http/cronet/AbsCallBack.kt +++ b/app/src/main/java/io/legado/app/help/http/cronet/AbsCallBack.kt @@ -148,7 +148,7 @@ abstract class AbsCallBack( override fun onCanceled(request: UrlRequest?, info: UrlResponseInfo?) { super.onCanceled(request, info) this.eventListener?.callEnd(mCall) - onError(IOException("Cronet Request Canceled")) + //onError(IOException("Cronet Request Canceled")) } diff --git a/app/src/main/java/io/legado/app/help/http/cronet/CronetCoroutineInterceptor.kt b/app/src/main/java/io/legado/app/help/http/cronet/CronetCoroutineInterceptor.kt new file mode 100644 index 000000000..542f8f504 --- /dev/null +++ b/app/src/main/java/io/legado/app/help/http/cronet/CronetCoroutineInterceptor.kt @@ -0,0 +1,106 @@ +package io.legado.app.help.http.cronet + +import io.legado.app.utils.printOnDebug +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.suspendCancellableCoroutine +import kotlinx.coroutines.withTimeout +import okhttp3.* +import okhttp3.internal.http.receiveHeaders +import org.chromium.net.UrlRequest +import org.chromium.net.UrlResponseInfo +import java.io.IOException +import kotlin.coroutines.resume +import kotlin.coroutines.resumeWithException + +class CronetCoroutineInterceptor(private val cookieJar: CookieJar = CookieJar.NO_COOKIES) : + Interceptor { + override fun intercept(chain: Interceptor.Chain): Response { + if (chain.call().isCanceled()) { + throw IOException("Canceled") + } + val original: Request = chain.request() + //Cronet未初始化 + return if (!CronetLoader.install() || cronetEngine == null) { + chain.proceed(original) + } else try { + val builder: Request.Builder = original.newBuilder() + //移除Keep-Alive,手动设置会导致400 BadRequest + builder.removeHeader("Keep-Alive") + builder.removeHeader("Accept-Encoding") + if (cookieJar != CookieJar.NO_COOKIES) { + val cookieStr = getCookie(original.url) + //设置Cookie + if (cookieStr.length > 3) { + builder.addHeader("Cookie", cookieStr) + } + } + + val newReq = builder.build() + val timeout = chain.call().timeout().timeoutNanos() / 1000000 + runBlocking() { + if (timeout > 0) { + withTimeout(timeout) { + proceedWithCronet(newReq, chain.call()).also { response -> + cookieJar.receiveHeaders(newReq.url, response.headers) + } + } + } else { + proceedWithCronet(newReq, chain.call()).also { response -> + cookieJar.receiveHeaders(newReq.url, response.headers) + } + } + } + + } catch (e: Exception) { + //不能抛出错误,抛出错误会导致应用崩溃 + //遇到Cronet处理有问题时的情况,如证书过期等等,回退到okhttp处理 + if (!e.message.toString().contains("ERR_CERT_", true) + && !e.message.toString().contains("ERR_SSL_", true) + ) { + e.printOnDebug() + } + chain.proceed(original) + } + + } + + + private suspend fun proceedWithCronet(request: Request, call: Call): Response = + suspendCancellableCoroutine { coroutine -> + + val callBack = object : AbsCallBack(originalRequest = request, mCall = call) { + override fun waitForDone(urlRequest: UrlRequest): Response { + TODO("Not yet implemented") + } + + override fun onError(error: IOException) { + coroutine.resumeWithException(error) + } + + override fun onSuccess(response: Response) { + coroutine.resume(response) + } + + override fun onCanceled(request: UrlRequest?, info: UrlResponseInfo?) { + super.onCanceled(request, info) + coroutine.cancel() + } + + + } + + buildRequest(request, callBack)?.start() + + + } + + + /** Returns a 'Cookie' HTTP request header with all cookies, like `a=b; c=d`. */ + private fun getCookie(url: HttpUrl): String = buildString { + val cookies = cookieJar.loadForRequest(url) + cookies.forEachIndexed { index, cookie -> + if (index > 0) append("; ") + append(cookie.name).append('=').append(cookie.value) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/lib/prefs/SwitchPreference.kt b/app/src/main/java/io/legado/app/lib/prefs/SwitchPreference.kt index 710959db0..7e1cdd49e 100644 --- a/app/src/main/java/io/legado/app/lib/prefs/SwitchPreference.kt +++ b/app/src/main/java/io/legado/app/lib/prefs/SwitchPreference.kt @@ -23,7 +23,7 @@ class SwitchPreference(context: Context, attrs: AttributeSet) : } override fun onBindViewHolder(holder: PreferenceViewHolder) { - super.onBindViewHolder(holder) + val v = Preference.bindView( context, holder, @@ -37,6 +37,7 @@ class SwitchPreference(context: Context, attrs: AttributeSet) : if (v is SwitchCompat && !v.isInEditMode) { v.applyTint(context.accentColor) } + super.onBindViewHolder(holder) onLongClick?.let { listener -> holder.itemView.setOnLongClickListener { listener.invoke(this) diff --git a/build.gradle b/build.gradle index 5abad1f95..d3323a07c 100644 --- a/build.gradle +++ b/build.gradle @@ -2,9 +2,9 @@ buildscript { ext{ - kotlin_version = '1.7.10' - compose_version = '1.2.1' - compose_compiler_version = '1.3.0' + kotlin_version = '1.7.20' + compose_version = '1.3.0-rc01' + compose_compiler_version = '1.3.2' agp_version = '7.3.1' exoplayer_version = '2.18.1' splitties_version = '3.0.0' @@ -16,7 +16,7 @@ plugins { id 'com.android.application' version "$agp_version" apply false id 'com.android.library' version "$agp_version" apply false id 'org.jetbrains.kotlin.android' version "$kotlin_version" apply false - id "de.undercouch.download" version "5.1.0" apply false + id "de.undercouch.download" version "5.2.1" apply false id "com.google.gms.google-services" version "4.3.10" apply false }