You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Kotlin Compose:调用onShowCustomView实现WebView全屏按钮失效求助

修复方案

核心问题分析

你的代码无法触发全屏的原因在于:

  • 按钮中创建了全新的CustomChromeClient实例,和WebView绑定的实例完全无关,调用其方法不会影响WebView的状态。
  • 直接手动调用onShowCustomView是错误的,该方法是WebChromeClient的回调,由WebView内部触发,手动调用缺少必要的View和回调参数。

修复后的完整代码

@Composable
fun Stream(activity: ComponentActivity) {
    val frameVideo = "<html><body><iframe width=\"300\" height=\"320\" src=\"https://static.videezy.com/system/resources/previews/000/000/168/original/Record.mp4\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen\" allowfullscreen></iframe></body></html>"
    val webViewState = rememberWebViewStateWithHTMLData(data = frameVideo)
    val navigator = rememberWebViewNavigator()
    val chromeClient = remember { CustomChromeClient(activity) }
    var webViewInstance by remember { mutableStateOf<WebView?>(null) }

    WebView(
        state = webViewState,
        modifier = Modifier.fillMaxSize(),
        navigator = navigator,
        chromeClient = chromeClient,
        onCreated = { webView ->
            webViewInstance = webView
            webView.settings.apply {
                javaScriptEnabled = true
                domStorageEnabled = true
                allowFileAccess = true
                allowContentAccess = true
                setSupportZoom(false)
                builtInZoomControls = false
            }
        }
    )

    FullScreenButton(onClick = {
        webViewInstance?.let { webView ->
            // 执行JS触发iframe内视频全屏
            webView.evaluateJavascript(
                """
                document.querySelector('iframe').requestFullscreen();
                """.trimIndent(),
                null
            )
        }
    })
}

@Composable
fun FullScreenButton(onClick: () -> Unit) {
    Column(
        modifier = Modifier.fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Bottom
    ) {
        Button(onClick = onClick) {
            Text("Full Screen")
        }
        Spacer(modifier = Modifier.height(32.dp))
    }
}

class CustomChromeClient(val activity: ComponentActivity) : AccompanistWebChromeClient() {
    private var customView: View? = null
    private var customViewCallback: CustomViewCallback? = null
    private val originalWindowFlags: Int = activity.window.attributes.flags

    override fun onShowCustomView(paramView: View, paramCustomViewCallback: CustomViewCallback) {
        if (customView != null) {
            paramCustomViewCallback.onCustomViewHidden()
            return
        }

        customView = paramView
        customViewCallback = paramCustomViewCallback

        // 隐藏系统UI,进入全屏模式
        activity.window.apply {
            addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN or WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS)
            decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                    or View.SYSTEM_UI_FLAG_FULLSCREEN
                    or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)
        }

        (activity.window.decorView as FrameLayout).addView(
            customView,
            FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)
        )
    }

    override fun onHideCustomView() {
        customView?.let {
            (activity.window.decorView as FrameLayout).removeView(it)
            customView = null
            customViewCallback?.onCustomViewHidden()
            customViewCallback = null

            // 恢复系统UI和窗口状态
            activity.window.apply {
                attributes.flags = originalWindowFlags
                decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE
            }
        }
    }
}

关键修复点说明

  1. 共享WebView实例:通过webViewInstance保存WebView的实例,让按钮可以调用其evaluateJavascript方法,触发页面内的全屏逻辑。
  2. 通过JS触发全屏:直接调用WebView的JS接口,让页面内的iframe元素请求全屏,这是符合WebView全屏逻辑的正确方式。
  3. 完善CustomChromeClient:
    • 保存原始窗口状态,退出全屏时恢复。
    • 添加系统UI隐藏逻辑,真正实现全屏效果。
    • 正确处理CustomViewCallback,避免内存泄漏。
  4. 修正WebView配置:移除重复的loadData调用,补充必要的WebSettings配置(如domStorageEnabled),确保JS正常执行。

额外注意事项

  • 确保你的Activity已经声明了android.permission.INTERNET权限(在AndroidManifest.xml中)。
  • 对于Android 11及以上版本,需要在Activity中处理WindowInsets,确保全屏时系统UI正确隐藏。
  • 部分视频网站可能有跨域限制,此时需要调整iframe的权限配置或JS逻辑。

内容的提问来源于stack exchange,提问作者SyahmiSam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 13:00:38