Compose 中使用 WebView

发布于:2025-05-09 ⋅ 阅读:(13) ⋅ 点赞:(0)

在 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)
            }
        }
    )
}

使用注意事项

  1. 添加网络权限:在 AndroidManifest.xml 中添加:

    <uses-permission android:name="android.permission.INTERNET" />
  2. WebView 优化

    settings.apply {
        javaScriptEnabled = true // 启用JS
        domStorageEnabled = true // 启用DOM存储
        cacheMode = WebSettings.LOAD_DEFAULT // 缓存模式
    }
  3. 内存管理:在 Activity 的 onDestroy 中调用 WebView.destroy() 防止内存泄漏

  4. 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 显示静态内容

最佳实践建议

  1. 简单需求:使用 Accompanist WebView

  2. 构建浏览器应用:考虑 Compose Browser

  3. 仅显示内容:HTML Viewer 更轻量

  4. 自定义需求:回退到原生 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 的复杂度,推荐根据项目需求选择合适的解决方案。


网站公告

今日签到

点亮在社区的每一天
去签到