Improve background WebView usage

This commit is contained in:
Koitharu
2025-09-17 09:27:10 +03:00
parent 43d3a2cc6a
commit f8687bb697
2 changed files with 35 additions and 30 deletions

View File

@@ -2,6 +2,7 @@ package org.koitharu.kotatsu.core.network.webview
import android.webkit.WebView
import android.webkit.WebViewClient
import kotlinx.coroutines.CancellableContinuation
import kotlin.coroutines.Continuation
import kotlin.coroutines.resume
@@ -14,7 +15,9 @@ open class ContinuationResumeWebViewClient(
}
protected fun resumeContinuation(view: WebView?) {
view?.webViewClient = WebViewClient() // reset to default
continuation.resume(Unit)
if (continuation !is CancellableContinuation || continuation.isActive) {
view?.webViewClient = WebViewClient() // reset to default
continuation.resume(Unit)
}
}
}

View File

@@ -3,9 +3,10 @@ package org.koitharu.kotatsu.core.network.webview
import android.content.Context
import android.webkit.WebSettings
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.annotation.MainThread
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
@@ -25,7 +26,6 @@ import java.lang.ref.WeakReference
import javax.inject.Inject
import javax.inject.Provider
import javax.inject.Singleton
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
@@ -47,16 +47,20 @@ class WebViewExecutor @Inject constructor(
suspend fun evaluateJs(baseUrl: String?, script: String): String? = mutex.withLock {
withContext(Dispatchers.Main.immediate) {
val webView = obtainWebView()
if (!baseUrl.isNullOrEmpty()) {
try {
if (!baseUrl.isNullOrEmpty()) {
suspendCoroutine { cont ->
webView.webViewClient = ContinuationResumeWebViewClient(cont)
webView.loadDataWithBaseURL(baseUrl, " ", "text/html", null, null)
}
}
suspendCoroutine { cont ->
webView.webViewClient = ContinuationResumeWebViewClient(cont)
webView.loadDataWithBaseURL(baseUrl, " ", "text/html", null, null)
}
}
suspendCoroutine { cont ->
webView.evaluateJavascript(script) { result ->
cont.resume(result?.takeUnless { it == "null" })
webView.evaluateJavascript(script) { result ->
cont.resume(result?.takeUnless { it == "null" })
}
}
} finally {
webView.reset()
}
}
}
@@ -69,23 +73,18 @@ class WebViewExecutor @Inject constructor(
exception.source.getUserAgent()?.let {
webView.settings.userAgentString = it
}
coroutineScope {
withTimeout(timeout) {
suspendCancellableCoroutine { cont ->
webView.webViewClient = CaptchaContinuationClient(
cookieJar = cookieJar,
targetUrl = exception.url,
continuation = cont,
)
cont.invokeOnCancellation {
webView.stopLoadingAsync()
}
webView.loadUrl(exception.url)
}
withTimeout(timeout) {
suspendCancellableCoroutine { cont ->
webView.webViewClient = CaptchaContinuationClient(
cookieJar = cookieJar,
targetUrl = exception.url,
continuation = cont,
)
webView.loadUrl(exception.url)
}
}
} finally {
webView.settings.userAgentString = defaultUserAgent
webView.reset()
}
}
}.onFailure { e ->
@@ -117,9 +116,12 @@ class WebViewExecutor @Inject constructor(
return repository?.getRequestHeaders()?.get(CommonHeaders.USER_AGENT)
}
private fun WebView.stopLoadingAsync() {
Dispatchers.Main.dispatch(EmptyCoroutineContext) {
stopLoading()
}
@MainThread
private fun WebView.reset() {
stopLoading()
webViewClient = WebViewClient()
settings.userAgentString = defaultUserAgent
loadDataWithBaseURL(null, " ", "text/html", null, null)
clearHistory()
}
}