
Batteries-included WebView toolkit with drop-in UI scaffolding, two-way JS bridge, file/camera/getUserMedia support, progress indicators and error page, debug log panel, optional QR scanner.
A batteries-included WebView SDK for Kotlin Multiplatform (Android + iOS) — UI scaffolding, a JS bridge, and file/camera support, all out of the box.
English | 中文
⚠️ Early access — the API may still change. See Releases.
window.KmpBridge.getUserMedia.Published on Maven Central — make sure mavenCentral() is in your repositories.
// KMP — declare once in commonMain; Gradle metadata resolves the platform artifacts
commonMain.dependencies {
implementation("wang.harlon:kmp-webview:0.1.3")
}
// Android-only project
implementation("wang.harlon:kmp-webview:0.1.3")| Platform | Requirement |
|---|---|
| Android | minSdk 24 |
| iOS | Integrate via KMP (iosArm64 / iosSimulatorArm64); getUserMedia needs iOS 14.5+ |
No standalone XCFramework yet — open an issue if you need one.
@Composable
fun MyScreen(onClose: () -> Unit) {
val state = rememberWebViewState("https://example.com")
WebViewScreen(state = state, onCloseRequest = onClose)
}Behavior is tuned through WebViewConfig: UA strategy, allow* toggles, a custom error-page slot, and bottom-bar / progress-bar visibility.
Register native handlers in Kotlin and call them from JS:
val state = rememberWebViewState("https://example.com")
state.jsBridge.registerHandler("getToken") { params -> """{"token":"${authRepo.fetchToken()}"}""" }
state.jsBridge.emit("auth.changed", """{"loggedIn":true}""")const token = await KmpBridge.call('getToken', { scope: 'user' });
const off = KmpBridge.on('auth.changed', payload => { /* ... */ });Handlers are suspend (String?) -> String?; throw JsBridgeException(code, message) to propagate an error code. The JS entry point (window.KmpBridge) can be renamed via rememberWebViewState(bridgeNamespace = "...").
See the JSBridge design, custom naming, and the frontend guide.
The SDK declares only INTERNET. Declare camera/microphone permissions yourself, only when you use those features.
Android — FileProvider is built in (no setup needed). For http:// URLs, enable usesCleartextTraffic or a network-security-config.
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" android:required="false" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />iOS — add the usage-description keys you need to Info.plist: NSCameraUsageDescription, NSMicrophoneUsageDescription, NSPhotoLibraryUsageDescription. getUserMedia is iOS 14.5+ only (no polyfill).
wang.harlon:kmp-webview-scanner is a separate module — the core library does not depend on it.
implementation("wang.harlon:kmp-webview-scanner:0.1.3")QrScannerScreen(
onResult = { url -> state.loadUrl(url); showScanner = false }, // only valid http/https URLs
onCancel = { showScanner = false },
)Built on CameraX + ZXing (offline, no Google Play Services). Only http/https URLs with a host are accepted; the module declares CAMERA itself and requests it on entry. See the design doc.
Set WebViewConfig(enableLogPanel = true) to inject an on-device, filterable log panel that captures JS console.*, uncaught JS errors, WebView load/resource errors, and JSBridge traffic.
Debug only — never enable in production. Bridge payloads enter the panel verbatim and may carry tokens or other sensitive data. The SDK does not redact them. When
false(the default), nothing is injected. See the design doc.
A batteries-included WebView SDK for Kotlin Multiplatform (Android + iOS) — UI scaffolding, a JS bridge, and file/camera support, all out of the box.
English | 中文
⚠️ Early access — the API may still change. See Releases.
window.KmpBridge.getUserMedia.Published on Maven Central — make sure mavenCentral() is in your repositories.
// KMP — declare once in commonMain; Gradle metadata resolves the platform artifacts
commonMain.dependencies {
implementation("wang.harlon:kmp-webview:0.1.3")
}
// Android-only project
implementation("wang.harlon:kmp-webview:0.1.3")| Platform | Requirement |
|---|---|
| Android | minSdk 24 |
| iOS | Integrate via KMP (iosArm64 / iosSimulatorArm64); getUserMedia needs iOS 14.5+ |
No standalone XCFramework yet — open an issue if you need one.
@Composable
fun MyScreen(onClose: () -> Unit) {
val state = rememberWebViewState("https://example.com")
WebViewScreen(state = state, onCloseRequest = onClose)
}Behavior is tuned through WebViewConfig: UA strategy, allow* toggles, a custom error-page slot, and bottom-bar / progress-bar visibility.
Register native handlers in Kotlin and call them from JS:
val state = rememberWebViewState("https://example.com")
state.jsBridge.registerHandler("getToken") { params -> """{"token":"${authRepo.fetchToken()}"}""" }
state.jsBridge.emit("auth.changed", """{"loggedIn":true}""")const token = await KmpBridge.call('getToken', { scope: 'user' });
const off = KmpBridge.on('auth.changed', payload => { /* ... */ });Handlers are suspend (String?) -> String?; throw JsBridgeException(code, message) to propagate an error code. The JS entry point (window.KmpBridge) can be renamed via rememberWebViewState(bridgeNamespace = "...").
See the JSBridge design, custom naming, and the frontend guide.
The SDK declares only INTERNET. Declare camera/microphone permissions yourself, only when you use those features.
Android — FileProvider is built in (no setup needed). For http:// URLs, enable usesCleartextTraffic or a network-security-config.
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" android:required="false" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />iOS — add the usage-description keys you need to Info.plist: NSCameraUsageDescription, NSMicrophoneUsageDescription, NSPhotoLibraryUsageDescription. getUserMedia is iOS 14.5+ only (no polyfill).
wang.harlon:kmp-webview-scanner is a separate module — the core library does not depend on it.
implementation("wang.harlon:kmp-webview-scanner:0.1.3")QrScannerScreen(
onResult = { url -> state.loadUrl(url); showScanner = false }, // only valid http/https URLs
onCancel = { showScanner = false },
)Built on CameraX + ZXing (offline, no Google Play Services). Only http/https URLs with a host are accepted; the module declares CAMERA itself and requests it on entry. See the design doc.
Set WebViewConfig(enableLogPanel = true) to inject an on-device, filterable log panel that captures JS console.*, uncaught JS errors, WebView load/resource errors, and JSBridge traffic.
Debug only — never enable in production. Bridge payloads enter the panel verbatim and may carry tokens or other sensitive data. The SDK does not redact them. When
false(the default), nothing is injected. See the design doc.