google / accompanist

A collection of extension libraries for Jetpack Compose
https://google.github.io/accompanist
Apache License 2.0
7.43k stars 598 forks source link

[WebView] Other Compose content not rendered while WebView is loading #1442

Closed dkarv closed 1 year ago

dkarv commented 1 year ago

Description While the Accompanist WebView is loading a url (we show a CircularProgressIndicator) it stops other Composable content from showing up. The other content is just white/blank. Please checkout this screencast of the issue: webview

Steps to reproduce

  1. Initialize webview, starts loading
  2. content above is not shown before the url is loaded

Expected behavior

  1. Initialize webview, start loading
  2. content above is shown all the time

Additional context The content above is not hidden or covered. It shows up as supposed in the Layout Inspector, it is just not shown on the real screen: Layout inspector

It seems like the WebView is internally blocking the other Compose rendering.

Compose Version: 1.3.1 Accompanist Version: 0.27.1

The WebView creation:

Box(modifier = modifier) {
        WebView(
            state = webviewState,
            client = webviewClient,
            chromeClient = webviewChromeClient,
            onCreated = {
                onCreated(it)
            }
        )
        val loadingState = webviewState.loadingState
        if (loadingState is LoadingState.Loading) {
            Box(
                modifier = Modifier
                    .padding(24.dp)
                    .fillMaxWidth(),
                contentAlignment = Alignment.Center
            ) {
                TestbirdsIndeterminateCircularProgressIndicator()
            }
        }
    }

The other content is in a Column, together with the WebView. I'm happy about any help or workarounds for this issue. I can provide more information if needed.

bentrengrove commented 1 year ago

This happens because on the first load of a webview it loads the whole chromium engine and that blocks Compose's applyChanges from happening. It is something I want to fix but haven't found a workaround for yet. Out of interest, does setting a Modifier.alpha(0.99f) fix the problem for you?

dkarv commented 1 year ago

Setting the alpha on the WebView fixed it on 3 out of 6 devices we tried. It works:

Does not work:

Based on the data it seems the fix does not work on Android 10 and 11 (we did not test Android 12).

nicolashaan commented 1 year ago

I have similar issues with the following snippet:

    val state = rememberWebViewState("https://www.notion.so")
    val navigator = rememberWebViewNavigator()
    Column(Modifier.background(Color.Red)) {
        Row(
            modifier = Modifier
                .height(56.dp)
                .fillMaxWidth(),
            horizontalArrangement = Arrangement.Start,
            verticalAlignment = Alignment.CenterVertically
        ) {
            IconButton(onClick = {}) {
                Icon(
                    Icons.Default.ArrowBack,
                    contentDescription = "go back"
                )
            }
        }
        WebView(
            state = state,
            navigator = navigator,
            onCreated = {
                it.settings.javaScriptEnabled = true
            }
        )
    }

Expected result:

Screenshot 2023-01-11 at 12 27 31

Actual result (Xiami Mi8, Android 10):

Screenshot 2023-01-11 at 12 37 23

@bentrengrove Could you confirm that it's the same root cause?

Here is a project reproducing the issue: https://github.com/nicolashaan/accompanist-webview-issue-repro

smithaaron commented 1 year ago

I have just encountered a similar issue. I notice that setting a height on the WebView fixes the problem, e.g. WebView( modifier = Modifier.height(300.dp),

I'm not a Compose expert, but this behaviour makes me assume that Column doesn't render its content until all Composables are finished measuring. Since the WebView is still loading it doesn't yet know its height, so this blocks the parent Column from rendering.

github-actions[bot] commented 1 year ago

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.

github-actions[bot] commented 1 year ago

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.

lyubomir-ganev-iu commented 1 year ago

I found by chance similar issue described on StackOverflow. One answer suggested to explicitly set the WebView's layer type to SOFTWARE like this:

webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null)

This solved all visible issue for us.

Here is the original answer: https://stackoverflow.com/a/75247593

benlu1117 commented 11 months ago

With webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null), the content of webView doesn't show after load for me. Still looking for other solution

waheed006 commented 10 months ago

This solves the issue: AndroidView( modifier = Modifier .fillMaxWidth() .weight(1f), factory = { WebView(context).apply { setLayerType(View.LAYER_TYPE_SOFTWARE, null) webViewClient = WebViewClient() loadUrl(item.link) } })

alvindizon commented 8 months ago

setLayerType(View.LAYER_TYPE_SOFTWARE, null) does not work if the content has GIFs

ln-12 commented 7 months ago

I know this issue is closed but my search lead me here first, so I want to make it easier for others to find this.

It seems like to correct solution is to set clipToOutline = true on the webview instance. See the issue tracker for reference and the source code for the current recommendation.

@bentrengrove would you agree with that?

bentrengrove commented 7 months ago

Yes, I believe that is correct

Rissmon commented 4 months ago

Below code worked for me:


AndroidView(modifier = modifier, factory = {
        WebView(it).apply {
            //setBackgroundColor(Color.Blue.toArgb())
            clipToOutline = true
        }
    }, update = {
        it.loadDataWithBaseURL(null, html, "text/html", "UTF-8", "")
    })