You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetpack Compose中如何在WebView创建逻辑外调用evaluateJavascript?

解决方案

核心思路采用单向数据流+事件驱动的实现方式,全程不在Composable以外持有WebView引用,通过ViewModel暴露可观察的JS调用事件,Compose侧监听事件触发WebView的API调用,完全符合官方开发规范。

具体实现步骤

  • 步骤1:改造ViewModel,移除WebView引用,替换为JS调用事件流
class SomeViewModel(application: Application): AndroidViewModel(application) {
    // 定义JS调用事件流,replay=0表示为一次性事件,不会重复消费
    private val _jsCommandFlow = MutableSharedFlow<String>(extraBufferCapacity = 1)
    val jsCommandFlow: SharedFlow<String> = _jsCommandFlow

    fun callJs(script: String = "updateSomething(123)") {
        // 向事件流发送JS调用请求
        viewModelScope.launch {
            _jsCommandFlow.emit(script)
        }
    }

    fun createWebAppInterface() : WebAppInterface {
        // 直接用applicationContext避免持有Activity上下文
        return WebAppInterface(getApplication(), ::callJs)
    }

    // 移除inner修饰符,避免隐式持有ViewModel引用
    class WebAppInterface(
        private val context: Context,
        private val onCallJs: () -> Unit
    ) {
        @JavascriptInterface
        fun webViewCallJs() {
            // Web端触发JS调用,直接走事件流
            onCallJs()
        }
    }
}
  • 步骤2:改造Composable,监听事件流触发WebView操作
@SuppressLint("SetJavaScriptEnabled")
@Composable
fun WebPageScreen(urlToRender: String, someViewModel: SomeViewModel) {
    AndroidView(
        factory = {
            WebView(it).apply {
                layoutParams = ViewGroup.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.MATCH_PARENT
                )
                webViewClient = WebViewClient()
                settings.javaScriptEnabled = true
                addJavascriptInterface(someViewModel.createWebAppInterface(), "Android")
                loadUrl(urlToRender)
            }
        },
        update = { webView ->
            // 监听JS调用事件流,有新事件时执行WebView API
            LaunchedEffect(Unit) {
                someViewModel.jsCommandFlow.collect { script ->
                    webView.evaluateJavascript(script, null)
                }
            }
            webView.loadUrl(urlToRender)
        }
    )
}

实现说明

  • 全程没有在Composable以外存储WebView引用,完全符合Jetpack Compose的官方规范,不会出现上下文泄漏问题
  • 双向调用需求完全覆盖:不管是ViewModel内部业务逻辑调用callJs(),还是Web端点击按钮触发webViewCallJs(),都会通过事件流通知Compose侧执行JS调用,逻辑统一
  • 配置变更(比如屏幕旋转)时,ViewModel不会销毁,事件流会正常工作,新的WebView实例创建后会自动监听事件流,不会丢失调用请求

内容的提问来源于stack exchange,提问作者duckduck

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 15:06:00