在 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<WebView?>(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 中添加:
<uses-permission android:name="android.permission.INTERNET" />
-
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 = """
<h1>标题</h1>
<p>这是一个段落</p>
"""
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 的复杂度,推荐根据项目需求选择合适的解决方案。