Type routing
type.When a WebView must read page state, receive host theme changes, or request native capabilities, the jsbridge module extends JavaScriptBridge with a shared JSValue protocol and message helpers.
| Scenario | Kotlin API | Web API | Result owner |
|---|---|---|---|
| Read title, price, or status | evaluateScriptValue |
none | Kotlin |
| Push theme or locale | postMessage |
window.wvbridge.addEventListener |
none |
| Kotlin asks web to run async work | postMessageAndReceiveResult |
listener calls reply |
Kotlin waits |
| Web requests share/save/auth | registerWebMessageHandlerWithReply |
postMessageAndReceiveResult |
Web waits |
| Web reports form or navigation state | registerWebMessageHandler |
window.wvbridge.postMessage |
none |
Type routing
type.One page API
window.wvbridge and evaluates it in the current page; future navigations get a document-start hook.evaluateScriptValue executes a function body, so use return; results are normalized to JSValue.
val result = controller.bridge.evaluateScriptValue(""" return { title: document.title, online: navigator.onLine };""".trimIndent())when (result) { is JSValue.Serializable -> render(result.value) is JSValue.Error -> showError(result.stacktrace) JSValue.Null, JSValue.Undefined -> showEmpty() is JSValue.ScriptObject -> showUnsupported(result.type)}asString(), asBoolean(), and asDouble() are strict conversions; use their OrNull variants for optional page data.
controller.bridge.postMessage("host:theme", JSValue.Serializable(payload))window.wvbridge.addEventListener("host:theme", theme => { document.documentElement.dataset.theme = theme.name;});Only Undefined, Null, and Serializable are valid outbound values. Register a matching listener before sending; otherwise the call fails with IllegalStateException.
val answer = controller.bridge.postMessageAndReceiveResult( "catalog:lookup", timeout = 5.seconds, JSValue.Serializable(query))The web listener receives a final reply callback and should invoke it exactly once. Conversely, registerWebMessageHandlerWithReply lets a web page await native work. Web-side timeout defaults to 30 seconds; late replies should be avoided.
val handle = controller.bridge.registerWebMessageHandler("checkout:changed") { values -> onCheckoutChanged(values.firstOrNull())}// close handle when the screen leaves compositionKeep the returned CloseHandle and close it with the screen lifecycle. Android registration requires AndroidX WebKit WEB_MESSAGE_LISTENER; unsupported runtimes throw UnsupportedOperationException.
window.wvbridge is public page API; window.__wvbridge__ is internal.JSValue.Error by evaluateScriptValue; native bridge errors may still throw.Dokka See evaluateScriptValue, postMessage, postMessageAndReceiveResult, and the jsbridge module.