new: add offline fallback support for WebView

This commit is contained in:
2026-07-08 12:47:38 +02:00
parent b063dfaff6
commit f6a12ad84a
14 changed files with 747 additions and 20 deletions
@@ -23,6 +23,7 @@ import platform.darwin.NSObject
@Composable
actual fun PlatformWebView(
url: String,
offlineHtml: String?,
darkTheme: Boolean,
onLoadingStateChange: (Boolean) -> Unit,
modifier: Modifier,
@@ -30,6 +31,8 @@ actual fun PlatformWebView(
// WKWebView holds its navigationDelegate weakly, so keep a strong reference across recompositions.
val navigationDelegate = remember { WebViewNavigationDelegate() }
navigationDelegate.onLoadingStateChange = onLoadingStateChange
navigationDelegate.offlineHtml = offlineHtml
navigationDelegate.baseUrl = url
UIKitView(
modifier = modifier,
@@ -54,12 +57,19 @@ actual fun PlatformWebView(
/**
* Forwards WKWebView load lifecycle events to [onLoadingStateChange] so the UI can show a loader
* while a page is loading and hide it once loading finishes (or fails).
* while a page is loading and hide it once loading finishes.
*
* When a navigation fails, it swaps in [offlineHtml] (loaded against [baseUrl] so links resolve) so
* the page still shows content offline. [showingOffline] guards against re-entering the fallback.
*/
private class WebViewNavigationDelegate :
NSObject(),
WKNavigationDelegateProtocol {
var onLoadingStateChange: (Boolean) -> Unit = {}
var offlineHtml: String? = null
var baseUrl: String = ""
private var showingOffline = false
override fun webView(
webView: WKWebView,
@@ -82,7 +92,7 @@ private class WebViewNavigationDelegate :
didFailNavigation: WKNavigation?,
withError: NSError,
) {
onLoadingStateChange(false)
handleFailure(webView)
}
// Shares the (WKWebView, WKNavigation?, NSError) Kotlin signature with didFailNavigation above.
@@ -92,7 +102,17 @@ private class WebViewNavigationDelegate :
didFailProvisionalNavigation: WKNavigation?,
withError: NSError,
) {
onLoadingStateChange(false)
handleFailure(webView)
}
private fun handleFailure(webView: WKWebView) {
val html = offlineHtml
if (html != null && !showingOffline) {
showingOffline = true
webView.loadHTMLString(string = html, baseURL = NSURL.URLWithString(baseUrl))
} else {
onLoadingStateChange(false)
}
}
}