diff --git a/CHANGELOG.md b/CHANGELOG.md
index d5ef5f18f..272587c86 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -41,6 +41,7 @@ The format is a modified version of [Keep a Changelog](https://keepachangelog.co
- Fixed the start and resume button going under the taskbar on tablets ([@AntsyLich](https://github.com/AntsyLich))
- Fixed a crash when updating an extension while others were installing ([@AntsyLich](https://github.com/AntsyLich))
- Fixed library entries without a date added getting their last update time as date added when updating from v0.20.x ([@AntsyLich](https://github.com/AntsyLich))
+- Fixed the app closing when WebView's page process crashed ([@AntsyLich](https://github.com/AntsyLich))
## [v0.21.0] - 2026-10-12
### Added
diff --git a/app/src/main/java/eu/kanade/presentation/webview/WebViewScreenContent.kt b/app/src/main/java/eu/kanade/presentation/webview/WebViewScreenContent.kt
index fbc26ff3f..7ff8c7ee2 100644
--- a/app/src/main/java/eu/kanade/presentation/webview/WebViewScreenContent.kt
+++ b/app/src/main/java/eu/kanade/presentation/webview/WebViewScreenContent.kt
@@ -5,8 +5,10 @@ import android.graphics.Bitmap
import android.os.Message
import android.webkit.JsPromptResult
import android.webkit.JsResult
+import android.webkit.RenderProcessGoneDetail
import android.webkit.WebResourceRequest
import android.webkit.WebView
+import android.widget.Toast
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
@@ -45,12 +47,15 @@ import eu.kanade.tachiyomi.BuildConfig
import eu.kanade.tachiyomi.util.system.getHtml
import eu.kanade.tachiyomi.util.system.setDefaultSettings
import eu.kanade.tachiyomi.util.system.setUserAgent
+import eu.kanade.tachiyomi.util.system.toast
import kotlinx.coroutines.launch
+import logcat.LogPriority
import mihon.icons.materialsymbols.MaterialSymbols
import mihon.icons.materialsymbols.automirroredrounded.ArrowBack
import mihon.icons.materialsymbols.automirroredrounded.ArrowForward
import mihon.icons.materialsymbols.rounded.Close
import mihon.icons.materialsymbols.rounded.TabClose
+import tachiyomi.core.common.util.system.logcat
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.Scaffold
import tachiyomi.presentation.core.i18n.stringResource
@@ -152,6 +157,17 @@ fun WebViewScreenContent(
return false
}
+
+ override fun onRenderProcessGone(view: WebView, detail: RenderProcessGoneDetail): Boolean {
+ // Not handling it kills the app along with the page
+ logcat(LogPriority.ERROR) {
+ "WebView renderer gone: crashed=${detail.didCrash()}, " +
+ "priority=${detail.rendererPriorityAtExit()}, url=$currentUrl"
+ }
+ view.context.toast(MR.strings.information_webview_crashed, Toast.LENGTH_LONG)
+ onNavigateUp()
+ return true
+ }
}
}
diff --git a/core/common/src/main/kotlin/eu/kanade/tachiyomi/network/interceptor/CloudflareInterceptor.kt b/core/common/src/main/kotlin/eu/kanade/tachiyomi/network/interceptor/CloudflareInterceptor.kt
index 7cc97fb01..3df2f876b 100644
--- a/core/common/src/main/kotlin/eu/kanade/tachiyomi/network/interceptor/CloudflareInterceptor.kt
+++ b/core/common/src/main/kotlin/eu/kanade/tachiyomi/network/interceptor/CloudflareInterceptor.kt
@@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.network.interceptor
import android.annotation.SuppressLint
import android.content.Context
import android.webkit.JavascriptInterface
+import android.webkit.RenderProcessGoneDetail
import android.webkit.WebResourceRequest
import android.webkit.WebResourceResponse
import android.webkit.WebView
@@ -13,12 +14,14 @@ import eu.kanade.tachiyomi.network.AndroidCookieJar
import eu.kanade.tachiyomi.util.system.isOutdated
import eu.kanade.tachiyomi.util.system.toast
import kotlinx.coroutines.CoroutineScope
+import logcat.LogPriority
import okhttp3.Cookie
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Interceptor
import okhttp3.Request
import okhttp3.Response
import tachiyomi.core.common.i18n.stringResource
+import tachiyomi.core.common.util.system.logcat
import tachiyomi.i18n.MR
import java.io.IOException
import java.util.concurrent.CountDownLatch
@@ -73,6 +76,7 @@ class CloudflareInterceptor(
var challengeFound = false
var cloudflareBypassed = false
var isWebViewOutdated = false
+ var isRenderProcessGone = false
val origRequestUrl = originalRequest.url.toString()
val headers = parseHeaders(originalRequest.headers)
@@ -140,6 +144,17 @@ class CloudflareInterceptor(
}
}
}
+
+ override fun onRenderProcessGone(view: WebView, detail: RenderProcessGoneDetail): Boolean {
+ // Not handling it kills the app, failing the bypass is enough
+ logcat(LogPriority.ERROR) {
+ "WebView renderer gone during Cloudflare bypass: crashed=${detail.didCrash()}, " +
+ "priority=${detail.rendererPriorityAtExit()}, url=$origRequestUrl"
+ }
+ isRenderProcessGone = true
+ latch.countDown()
+ return true
+ }
}
webview.loadUrl(origRequestUrl, headers)
@@ -148,12 +163,13 @@ class CloudflareInterceptor(
latch.awaitFor30Seconds()
executor.execute {
- if (!cloudflareBypassed) {
+ // Only destroy can be called on a WebView whose renderer is gone
+ if (!cloudflareBypassed && !isRenderProcessGone) {
isWebViewOutdated = webview?.isOutdated() == true
}
webview?.run {
- stopLoading()
+ if (!isRenderProcessGone) stopLoading()
destroy()
}
}
diff --git a/i18n/src/commonMain/moko-resources/base/strings.xml b/i18n/src/commonMain/moko-resources/base/strings.xml
index 19925c456..d54c7a7f0 100644
--- a/i18n/src/commonMain/moko-resources/base/strings.xml
+++ b/i18n/src/commonMain/moko-resources/base/strings.xml
@@ -1020,6 +1020,8 @@
WebView is required for the app to function
Please update the WebView app for better compatibility
+
+ WebView stopped working and the page was closed
Updated default chapter settings