Exception in newer Android
Library version: 2.0.3, Android device: 10, Kotlin 2.0.21, latest dependencies.
Card(Modifier.widthIn(max = 300.dp), RoundedCornerShape(16.dp), cardColors) {
if (html != null) {
if (fullWebView) WebView(
html
.formatHtmlForSurfaceColor(cardContainerColor)
.also {
ld { "Loading HTML: $it" }
},
Modifier.heightIn(max = 500.dp)
)
}
else Text(html)
}
@Composable
actual fun WebView(html: String, modifier: Modifier) {
val state = rememberWebViewStateWithHTMLData(data = html)
com.multiplatform.webview.web.WebView(state = state, modifier = modifier)
}
2025-11-05 16:09:19.379 9498-9498 myapp com...myapp D Loading HTML: <ul><li>test</li></ul>
2025-11-05 16:09:19.418 9498-9498 WebViewFactory com...myapp I Loading com.google.android.webview version 141.0.7390.122 (code 739012230)
2025-11-05 16:09:19.557 9498-9498 WebViewFactory com...myapp E error instantiating provider (Ask Gemini)
java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Native Method)
at android.webkit.WebViewFactory.getProvider(WebViewFactory.java:266)
at android.webkit.CookieManager.getInstance(CookieManager.java:50)
at com.multiplatform.webview.cookie.AndroidCookieManager.<clinit>(AndroidCookieManager.kt:16)
at com.multiplatform.webview.cookie.AndroidCookieManagerKt.WebViewCookieManager(AndroidCookieManager.kt:162)
at com.multiplatform.webview.web.WebViewState.<init>(WebViewState.kt:101)
at com.multiplatform.webview.web.WebViewStateKt.rememberWebViewStateWithHTMLData(WebViewState.kt:213)
at myapp.ui.components.common.html.WebView_androidKt.WebView(WebView.android.kt:9)
at myapp.ui.components.domain.MessageCardKt.MessageCard$lambda$4$2(MessageCard.kt:144)
at myapp.ui.components.domain.MessageCardKt.$r8$lambda$5lhIKeq6gu30ew-0iT_AQysDllA(Unknown Source:0)
at myapp.ui.components.domain.MessageCardKt$$ExternalSyntheticLambda8.invoke(D8$$SyntheticClass:0)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:130)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke$lambda$0(ComposableLambda.kt:132)
at androidx.compose.runtime.internal.ComposableLambdaImpl.$r8$lambda$qz3voikrQeNn5XJEtUlXR2wfzBw(Unknown Source:0)
at androidx.compose.runtime.internal.ComposableLambdaImpl$$ExternalSyntheticLambda16.invoke(D8$$SyntheticClass:0)
at androidx.compose.runtime.RecomposeScopeImpl.compose(RecomposeScopeImpl.kt:196)
at androidx.compose.runtime.ComposerImpl.recomposeToGroupEnd(Composer.kt:2895)
at androidx.compose.runtime.ComposerImpl.skipToGroupEnd(Composer.kt:3289)
at androidx.compose.material3.CardKt.Card(Card.kt:79)
at myapp.ui.components.domain.MessageCardKt.MessageCard(MessageCard.kt:137)
at myapp.ui.components.domain.MessageCardKt.MessageCard$lambda$5(Unknown Source:6)
at myapp.ui.components.domain.MessageCardKt.$r8$lambda$jIpA4lsJgUiJ7XrhhdYuv_S1CdM(Unknown Source:0)
at myapp.ui.components.domain.MessageCardKt$$ExternalSyntheticLambda9.invoke(D8$$SyntheticClass:0)
at androidx.compose.runtime.RecomposeScopeImpl.compose(RecomposeScopeImpl.kt:196)
at androidx.compose.runtime.ComposerImpl.recomposeToGroupEnd(Composer.kt:2895)
at androidx.compose.runtime.ComposerImpl.skipCurrentGroup(Composer.kt:3231)
at androidx.compose.runtime.ComposerImpl.doCompose-aFTiNEg(Composer.kt:3855)
at androidx.compose.runtime.ComposerImpl.recompose-aFTiNEg$runtime(Composer.kt:3779)
at androidx.compose.runtime.CompositionImpl.recompose(Composition.kt:1075)
at androidx.compose.runtime.Recomposer.performRecompose(Recomposer.kt:1373)
at androidx.compose.runtime.Recomposer.access$performRecompose(Recomposer.kt:156)
at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2.invokeSuspend$lambda$22(Recomposer.kt:627)
at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2.$r8$lambda$OqADLCDYmRw1RgNUvn1CR0kX32M(Unknown Source:0)
at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$$ExternalSyntheticLambda0.invoke(D8$$SyntheticClass:0)
at androidx.compose.ui.platform.AndroidUiFrameClock$withFrameNanos$2$callback$1.doFrame(AndroidUiFrameClock.android.kt:39)
at androidx.compose.ui.platform.AndroidUiDispatcher.performFrameDispatch(AndroidUiDispatcher.android.kt:108)
at androidx.compose.ui.platform.AndroidUiDispatcher.access$performFrameDispatch(AndroidUiDispatcher.android.kt:41)
at androidx.compose.ui.platform.AndroidUiDispatcher$dispatchCallback$1.doFrame(AndroidUiDispatcher.android.kt:69)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1008)
at android.view.Choreographer.doCallbacks(Choreographer.java:809)
at android.view.Choreographer.doFrame(Choreographer.java:740)
--------- beginning of crash
2025-11-05 16:09:19.558 9498-9498 WebViewFactory com...myapp E at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:995) (Ask Gemini)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:246)
at android.app.ActivityThread.main(ActivityThread.java:8653)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130)
Caused by: java.lang.RuntimeException: Package not found: com.google.android.webview
at android.webkit.WebViewDelegate.getPackageId(WebViewDelegate.java:191)
at com.android.webview.chromium.WebViewChromiumFactoryProvider.<init>(chromium-TrichromeWebViewGoogle.aab-stable-739012230:404)
at com.android.webview.chromium.WebViewChromiumFactoryProviderForR.<init>(chromium-TrichromeWebViewGoogle.aab-stable-739012230:1)
at com.android.webview.chromium.WebViewChromiumFactoryProviderForR.create(chromium-TrichromeWebViewGoogle.aab-stable-739012230:3)
... 49 more
2025-11-05 16:09:19.579 9498-9498 AndroidRuntime com...myapp E FATAL EXCEPTION: main (Ask Gemini)
Process: com.myapp, PID: 9498
java.lang.ExceptionInInitializerError
at com.multiplatform.webview.cookie.AndroidCookieManagerKt.WebViewCookieManager(AndroidCookieManager.kt:162)
at com.multiplatform.webview.web.WebViewState.<init>(WebViewState.kt:101)
at com.multiplatform.webview.web.WebViewStateKt.rememberWebViewStateWithHTMLData(WebViewState.kt:213)
at myapp.ui.components.common.html.WebView_androidKt.WebView(WebView.android.kt:9)
at myapp.ui.components.domain.MessageCardKt.MessageCard$lambda$4$2(MessageCard.kt:144)
at myapp.ui.components.domain.MessageCardKt.$r8$lambda$5lhIKeq6gu30ew-0iT_AQysDllA(Unknown Source:0)
at myapp.ui.components.domain.MessageCardKt$$ExternalSyntheticLambda8.invoke(D8$$SyntheticClass:0)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:130)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke$lambda$0(ComposableLambda.kt:132)
at androidx.compose.runtime.internal.ComposableLambdaImpl.$r8$lambda$qz3voikrQeNn5XJEtUlXR2wfzBw(Unknown Source:0)
at androidx.compose.runtime.internal.ComposableLambdaImpl$$ExternalSyntheticLambda16.invoke(D8$$SyntheticClass:0)
at androidx.compose.runtime.RecomposeScopeImpl.compose(RecomposeScopeImpl.kt:196)
at androidx.compose.runtime.ComposerImpl.recomposeToGroupEnd(Composer.kt:2895)
at androidx.compose.runtime.ComposerImpl.skipToGroupEnd(Composer.kt:3289)
at androidx.compose.material3.CardKt.Card(Card.kt:79)
at myapp.ui.components.domain.MessageCardKt.MessageCard(MessageCard.kt:137)
at myapp.ui.components.domain.MessageCardKt.MessageCard$lambda$5(Unknown Source:6)
at myapp.ui.components.domain.MessageCardKt.$r8$lambda$jIpA4lsJgUiJ7XrhhdYuv_S1CdM(Unknown Source:0)
at myapp.ui.components.domain.MessageCardKt$$ExternalSyntheticLambda9.invoke(D8$$SyntheticClass:0)
at androidx.compose.runtime.RecomposeScopeImpl.compose(RecomposeScopeImpl.kt:196)
at androidx.compose.runtime.ComposerImpl.recomposeToGroupEnd(Composer.kt:2895)
at androidx.compose.runtime.ComposerImpl.skipCurrentGroup(Composer.kt:3231)
at androidx.compose.runtime.ComposerImpl.doCompose-aFTiNEg(Composer.kt:3855)
at androidx.compose.runtime.ComposerImpl.recompose-aFTiNEg$runtime(Composer.kt:3779)
at androidx.compose.runtime.CompositionImpl.recompose(Composition.kt:1075)
at androidx.compose.runtime.Recomposer.performRecompose(Recomposer.kt:1373)
at androidx.compose.runtime.Recomposer.access$performRecompose(Recomposer.kt:156)
at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2.invokeSuspend$lambda$22(Recomposer.kt:627)
at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2.$r8$lambda$OqADLCDYmRw1RgNUvn1CR0kX32M(Unknown Source:0)
at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$$ExternalSyntheticLambda0.invoke(D8$$SyntheticClass:0)
at androidx.compose.ui.platform.AndroidUiFrameClock$withFrameNanos$2$callback$1.doFrame(AndroidUiFrameClock.android.kt:39)
at androidx.compose.ui.platform.AndroidUiDispatcher.performFrameDispatch(AndroidUiDispatcher.android.kt:108)
at androidx.compose.ui.platform.AndroidUiDispatcher.access$performFrameDispatch(AndroidUiDispatcher.android.kt:41)
at androidx.compose.ui.platform.AndroidUiDispatcher$dispatchCallback$1.doFrame(AndroidUiDispatcher.android.kt:69)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1008)
at android.view.Choreographer.doCallbacks(Choreographer.java:809)
at android.view.Choreographer.doFrame(Choreographer.java:740)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:995)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:246)
at android.app.ActivityThread.main(ActivityThread.java:8653)
2025-11-05 16:09:19.580 9498-9498 AndroidRuntime com...myapp E at java.lang.reflect.Method.invoke(Native Method) (Ask Gemini)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130)
Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [androidx.compose.runtime.PausableMonotonicFrameClock@a2e45a3, androidx.compose.ui.platform.MotionDurationScaleImpl@dfd80a0, StandaloneCoroutine{Cancelling}@de0b459, AndroidUiDispatcher@576181e]
Caused by: android.util.AndroidRuntimeException: java.lang.reflect.InvocationTargetException
at android.webkit.WebViewFactory.getProvider(WebViewFactory.java:271)
at android.webkit.CookieManager.getInstance(CookieManager.java:50)
at com.multiplatform.webview.cookie.AndroidCookieManager.<clinit>(AndroidCookieManager.kt:16)
... 45 more
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Native Method)
at android.webkit.WebViewFactory.getProvider(WebViewFactory.java:266)
... 47 more
Caused by: java.lang.RuntimeException: Package not found: com.google.android.webview
at android.webkit.WebViewDelegate.getPackageId(WebViewDelegate.java:191)
at com.android.webview.chromium.WebViewChromiumFactoryProvider.<init>(chromium-TrichromeWebViewGoogle.aab-stable-739012230:404)
at com.android.webview.chromium.WebViewChromiumFactoryProviderForR.<init>(chromium-TrichromeWebViewGoogle.aab-stable-739012230:1)
at com.android.webview.chromium.WebViewChromiumFactoryProviderForR.create(chromium-TrichromeWebViewGoogle.aab-stable-739012230:3)
... 49 more
@KevinnZou The issue lies in this line: https://github.com/KevinnZou/compose-webview-multiplatform/blob/ed86a62809bea429a2b80ded716accc6f647b502/webview/src/commonMain/kotlin/com/multiplatform/webview/web/WebViewState.kt#L101
That initialization runs as soon as WebViewState is constructed (i.e., during composition when you call rememberWebViewStateWithHTMLData(...)). Inside WebViewCookieManager() (per the stack trace), the Android CookieManager.getInstance() is touched in a static initializer. If that happens before WebView’s provider is safely available (e.g., secondary process without data directory suffix, or too early in app startup, or not on the UI thread), Android fails with WebViewFactory ... error instantiating provider.
Fix
Instead of constructing the cookie manager in the property initializer, make it lazy and only touch it after a real WebView exists (and on the main thread).
class WebViewState(
webContent: WebContent,
) {
// ... existing properties ...
// Defer construction, and ensure we are on the main thread when accessed
val cookieManager: CookieManager by lazy(LazyThreadSafetyMode.NONE) {
ensureMainThread()
WebViewCookieManager()
}
private fun ensureMainThread() {
check(Looper.getMainLooper() == Looper.myLooper()) {
"CookieManager must be accessed on the main (UI) thread"
}
}
Then, only access state.cookieManager from places that run on the UI thread after you’ve created the actual Android WebView (e.g., inside AndroidView(factory = { ... }) block).
AndroidView(
factory = { context ->
WebView(context).apply {
// The provider is materialized here; now it’s safe to touch CookieManager.
// Trigger lazy init explicitly after WebView exists:
state.cookieManager // this invokes the lazy block
}
},
update = { /* ... */ }
)
This also works:
@Composable
fun SafeWebView(html: String, modifier: Modifier) {
var mount by rememberSaveable { mutableStateOf(false) }
// Wait one frame before composing the library's WebView
LaunchedEffect(Unit) {
// Suspend until the next frame
withFrameNanos { /* no-op */ }
mount = true
}
if (mount) {
lv { "Mounting" }
val state = rememberWebViewStateWithHTMLData(html)
com.multiplatform.webview.web.WebView(state = state, modifier = modifier)
}
}
@ShmuelCammebys Thanks for your suggestion, just feel free to submit a PR. I will review and merge it.