Skip to content

JavaScript enhancement utilities

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.

  1. Choose a message model
  2. Evaluate structured data
  3. Send events
  4. Request and reply
  5. Register web notifications
  6. Boundaries and API reference
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

Handlers receive only envelopes with their registered application-defined type.

One page API

First use installs 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 composition

Keep 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.
  • Origin, frame, and security policy remain platform WebView responsibilities; treat web origins as untrusted.
  • Script execution failures are represented as JSValue.Error by evaluateScriptValue; native bridge errors may still throw.

Dokka See evaluateScriptValue, postMessage, postMessageAndReceiveResult, and the jsbridge module.