Compose 中使用 WebView
在 Jetpack Compose 中,我们可以使用 AndroidView 组件来集成传统的 Android WebView。以下是几种实现方式:
基础 WebView 实现
@Composable fun WebViewScreen(url: String) { AndroidView( factory = { context -> WebView(context).apply { // 设置布局参数 layoutParams = ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT ) // 设置 WebViewClient webViewClient = WebViewClient() // 加载网址 loadUrl(url) } } ) }
增强版 WebView(带更多控制)
@Composable fun EnhancedWebView( url: String, modifier: Modifier = Modifier, onPageStarted: (String?) -> Unit = {}, // 页面开始加载回调 onPageFinished: (String?) -> Unit = {}, // 页面加载完成回调 onError: (WebResourceError?) -> Unit = {}, // 加载错误回调 onProgressChanged: (Int) -> Unit = {} // 加载进度变化回调 ) { val context = LocalContext.current AndroidView( modifier = modifier, factory = { ctx -> WebView(ctx).apply { webViewClient = object : WebViewClient() { override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) { onPageStarted(url) } override fun onPageFinished(view: WebView?, url: String?) { onPageFinished(url) } override fun onReceivedError( view: WebView?, errorCode: Int, description: String?, failingUrl: String? ) { onError(WebResourceError(errorCode, description ?: "")) } } webChromeClient = object : WebChromeClient() { override fun onProgressChanged(view: WebView?, newProgress: Int) { onProgressChanged(newProgress) } } settings.javaScriptEnabled = true // 启用JavaScript loadUrl(url) } } ) }
带有返回按钮控制的 WebView
@Composable fun WebViewWithBackHandler(url: String) { val webView = remember { mutableStateOf(null) } val context = LocalContext.current // 处理返回按钮 BackHandler(enabled = webView.value?.canGoBack() == true) { webView.value?.goBack() } AndroidView( factory = { ctx -> WebView(ctx).apply { webView.value = this webViewClient = WebViewClient() loadUrl(url) } } ) }
使用注意事项
-
添加网络权限:在 AndroidManifest.xml 中添加:
-
WebView 优化:
settings.apply { javaScriptEnabled = true // 启用JS domStorageEnabled = true // 启用DOM存储 cacheMode = WebSettings.LOAD_DEFAULT // 缓存模式 }
-
内存管理:在 Activity 的 onDestroy 中调用 WebView.destroy() 防止内存泄漏
-
Compose 限制:由于 WebView 是传统 View,某些高级 Compose 功能可能无法直接应用
完整示例使用
@Composable fun WebViewExample() { var url by remember { mutableStateOf("https://www.example.com") } var loadingProgress by remember { mutableStateOf(0) } var isLoading by remember { mutableStateOf(false) } Column(modifier = Modifier.fillMaxSize()) { // 加载进度条 if (isLoading) { LinearProgressIndicator( progress = loadingProgress / 100f, modifier = Modifier.fillMaxWidth() ) } // WebView 组件 EnhancedWebView( url = url, modifier = Modifier.weight(1f), onPageStarted = { isLoading = true }, onPageFinished = { isLoading = false }, onProgressChanged = { loadingProgress = it }, onError = { error -> Toast.makeText(context, "加载错误: ${error.description}", Toast.LENGTH_SHORT).show() } ) } }
这样就能在 Compose 应用中完整地集成和使用 WebView 了。
有第三方库支持
Compose 中使用 WebView 的第三方库
在 Jetpack Compose 中,除了使用原生 AndroidView 集成 WebView 外,还有一些优秀的第三方库可以简化 WebView 的使用。以下是几个常用的库:
1. Accompanist WebView (官方推荐)
Google Accompanist 提供的 WebView 库,目前最流行的选择。
添加依赖:
implementation "com.google.accompanist:accompanist-webview:0.34.0"
基本用法:
@Composable fun WebViewSample() { val state = rememberWebViewState("https://example.com") WebView( state = state, modifier = Modifier.fillMaxSize(), onCreated = { webView -> webView.settings.javaScriptEnabled = true } ) }
特性:
-
内置状态管理 (rememberWebViewState)
-
支持导航历史
-
加载进度监听
(图片来源网络,侵删) -
与 Compose 生命周期完美集成
2. Compose WebView
另一个专门为 Compose 设计的 WebView 库。
(图片来源网络,侵删)添加依赖:
implementation "io.github.kevinnzou:compose-webview:1.6.0"
基本用法:
(图片来源网络,侵删)@Composable fun WebViewExample() { val webView = rememberWebView() WebView( webView = webView, url = "https://example.com", modifier = Modifier.fillMaxSize(), onPageStarted = { url -> /* 页面开始加载 */ }, onPageFinished = { url -> /* 页面加载完成 */ } ) }
特性:
-
更简洁的 API
-
支持 JavaScript 桥接
-
内置下载管理器支持
3. Compose Browser
功能更丰富的浏览器组件库。
添加依赖:
implementation "com.moriatsushi.compose:compose-browser:0.1.0"
高级用法:
@Composable fun BrowserSample() { val controller = rememberBrowserController("https://example.com") Browser( controller = controller, modifier = Modifier.fillMaxSize(), onTitleChanged = { title -> /* 标题变化 */ }, onUrlChanged = { url -> /* URL 变化 */ } ) // 控制导航 Button(onClick = { controller.goBack() }) { Text("返回") } }
4. Compose HTML Viewer
如果只需要显示简单 HTML 内容(不需要完整 WebView 功能)
添加依赖:
implementation "com.github.jeziellago:compose-markdown:0.3.4"
显示 HTML:
@Composable fun HtmlViewer() { val html = """
标题
这是一个段落
""" HtmlText(html = html, modifier = Modifier.padding(16.dp)) }综合比较
库名称 优点 缺点 适用场景 Accompanist WebView 官方维护,功能全面 API 相对复杂 需要完整 WebView 功能 Compose WebView API 简洁,易用 功能较少 简单 WebView 需求 Compose Browser 导航控制方便 较新,文档少 需要构建浏览器应用 HTML Viewer 轻量级 仅支持简单 HTML 显示静态内容 最佳实践建议
-
简单需求:使用 Accompanist WebView
-
构建浏览器应用:考虑 Compose Browser
-
仅显示内容:HTML Viewer 更轻量
-
自定义需求:回退到原生 AndroidView 实现
完整示例(使用 Accompanist):
@Composable fun FullFeaturedWebView() { var canGoBack by remember { mutableStateOf(false) } val state = rememberWebViewState("https://example.com") val navigator = rememberWebViewNavigator() Column(modifier = Modifier.fillMaxSize()) { // 顶部控制栏 Row(verticalAlignment = Alignment.CenterVertically) { IconButton( onClick = { navigator.goBack() }, enabled = canGoBack ) { Icon(Icons.Default.ArrowBack, "返回") } Text( text = state.pageTitle ?: "加载中...", modifier = Modifier.weight(1f), maxLines = 1, overflow = TextOverflow.Ellipsis ) CircularProgressIndicator( progress = state.loadingProgress / 100f, modifier = Modifier.size(24.dp) ) } // WebView 主体 WebView( state = state, navigator = navigator, modifier = Modifier.weight(1f), onCreated = { webView -> webView.settings.apply { javaScriptEnabled = true domStorageEnabled = true } } ) } // 监听导航状态 LaunchedEffect(navigator.canGoBack) { canGoBack = navigator.canGoBack } }
这些第三方库可以大大简化在 Compose 中使用 WebView 的复杂度,推荐根据项目需求选择合适的解决方案。
-
-