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 } } } }
关键修复点说明
- 共享WebView实例:通过
webViewInstance保存WebView的实例,让按钮可以调用其evaluateJavascript方法,触发页面内的全屏逻辑。 - 通过JS触发全屏:直接调用WebView的JS接口,让页面内的iframe元素请求全屏,这是符合WebView全屏逻辑的正确方式。
- 完善CustomChromeClient:
- 保存原始窗口状态,退出全屏时恢复。
- 添加系统UI隐藏逻辑,真正实现全屏效果。
- 正确处理CustomViewCallback,避免内存泄漏。
- 修正WebView配置:移除重复的
loadData调用,补充必要的WebSettings配置(如domStorageEnabled),确保JS正常执行。
额外注意事项
- 确保你的Activity已经声明了
android.permission.INTERNET权限(在AndroidManifest.xml中)。 - 对于Android 11及以上版本,需要在Activity中处理WindowInsets,确保全屏时系统UI正确隐藏。
- 部分视频网站可能有跨域限制,此时需要调整iframe的权限配置或JS逻辑。
内容的提问来源于stack exchange,提问作者SyahmiSam
相关产品推荐
相关产品推荐

