Jetpack Compose WebView中IFrame视频全屏实现求助
Jetpack Compose WebView IFrame视频全屏实现方案
核心思路
要实现IFrame视频全屏,关键是通过WebChromeClient拦截全屏请求,切换Compose布局显示视频视图;同时配置WebView的基础参数,确保视频能触发全屏逻辑。
具体实现步骤
- 配置WebView基础参数
开启JavaScript、允许媒体播放相关权限,这些是视频全屏的前提:
webView.settings.apply { javaScriptEnabled = true domStorageEnabled = true mediaPlaybackRequiresUserGesture = false // 按需开启,允许视频自动播放 allowFileAccess = true setSupportZoom(false) builtInZoomControls = false displayZoomControls = false }
- 自定义WebChromeClient处理全屏逻辑
实现onShowCustomView和onHideCustomView方法,这两个方法会在视频进入/退出全屏时被调用,我们需要在这里更新全屏状态并处理系统UI:
private inner class CustomWebChromeClient( private val onFullScreenChanged: (Boolean, View?) -> Unit ) : WebChromeClient() { private var customViewCallback: CustomViewCallback? = null override fun onShowCustomView(view: View?, callback: CustomViewCallback?) { super.onShowCustomView(view, callback) customViewCallback = callback onFullScreenChanged(true, view) // 隐藏系统状态栏和导航栏,实现沉浸式全屏 requireActivity().window.decorView.systemUiVisibility = ( View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY ) } override fun onHideCustomView() { super.onHideCustomView() customViewCallback?.onCustomViewHidden() onFullScreenChanged(false, null) // 恢复系统UI显示 requireActivity().window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE } }
- Compose布局中集成WebView与全屏视图
用remember保存全屏状态和视频视图,根据状态切换显示WebView还是全屏视频:
@Composable fun WebViewScreen(onFullScreenChanged: (Boolean) -> Unit) { var isFullScreen by remember { mutableStateOf(false) } var fullScreenView by remember { mutableStateOf<View?>(null) } LaunchedEffect(isFullScreen) { onFullScreenChanged(isFullScreen) } if (isFullScreen && fullScreenView != null) { // 全屏状态下仅显示视频视图 AndroidView(factory = { fullScreenView!! }) } else { // 非全屏状态显示WebView AndroidView( factory = { context -> WebView(context).apply { webChromeClient = CustomWebChromeClient { fullScreen, view -> isFullScreen = fullScreen fullScreenView = view } settings.apply { javaScriptEnabled = true domStorageEnabled = true mediaPlaybackRequiresUserGesture = false allowFileAccess = true setSupportZoom(false) builtInZoomControls = false displayZoomControls = false } // 加载包含IFrame的页面,替换为你的实际内容 loadData( "<html><body><iframe width='100%' height='300' src='https://www.youtube.com/embed/your-video-id' frameborder='0' allow='autoplay; fullscreen'></iframe></body></html>", "text/html", "utf-8" ) } } ) } }
- 处理返回键退出全屏
在MainActivity中重写返回逻辑,优先退出全屏再处理页面返回:
class MainActivity : ComponentActivity() { private var isFullScreen by mutableStateOf(false) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { YourAppTheme { WebViewScreen(onFullScreenChanged = { isFullScreen = it }) } } onBackPressedDispatcher.addCallback(this) { if (isFullScreen) { isFullScreen = false window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE this.isEnabled = false onBackPressedDispatcher.onBackPressed() } else { finish() } } } }
崩溃问题排查
如果集成后出现崩溃,大概率是以下原因:
- 空指针异常:
onShowCustomView中view为空,需添加非空判断; - 视图重复添加:全屏视图未正确从父容器移除,可在
onHideCustomView中调用fullScreenView?.parent?.let { (it as ViewGroup).removeView(fullScreenView) }; - 配置变化丢失状态:用
rememberSaveable替代remember保存isFullScreen状态(View无法直接序列化,仅保存状态标记即可)。
内容的提问来源于stack exchange,提问作者SyahmiSam
相关产品推荐
相关产品推荐

