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

Jetpack Compose中AndroidView(WebView)可点击词条功能失效排查

解决Jetpack Compose中WebView点击词条触发Toast的问题

你的代码已经完成了Android与WebView的JS交互基础配置,但核心问题在于HTML内容里的词条没有绑定触发JS调用Android方法的逻辑,所以点击不会有反应。下面是具体的修复方案:

1. 给HTML词条添加点击交互逻辑

需要将可点击的词条包装成可交互的HTML元素,并绑定点击事件调用Android端的showToast方法。你可以选择两种方式:

方式一:手动给目标词条添加点击事件

在传入的htmlContent中,将需要点击的词条用<span>(或其他元素)包裹,并添加onclick事件:

// 调用示例
HtmlText(htmlContent = "<span onclick='Android.showToast(this.innerText)'>测试词条1</span> <span onclick='Android.showToast(this.innerText)'>测试词条2</span>")

方式二:自动给所有目标元素绑定点击事件

如果需要批量处理词条,可以在HTML模板中添加JS脚本,自动给指定类名的元素绑定点击逻辑,这样无需修改传入的htmlContent内容:
修改rightAlignedHtmlContent的模板:

val rightAlignedHtmlContent = """
    <html>
    <head>
        <style>
            body {
                text-align: right;
            }
            .clickable-entry {
                color: #1a73e8;
                text-decoration: underline;
                cursor: pointer;
            }
        </style>
    </head>
    <body>
        $htmlContent
        <script type="text/javascript">
            // 自动给所有带有clickable-entry类的元素绑定点击事件
            document.querySelectorAll('.clickable-entry').forEach(element => {
                element.addEventListener('click', function() {
                    Android.showToast(this.innerText);
                });
            });
        </script>
    </body>
    </html>
""".trimIndent()

此时传入的htmlContent只需给词条添加clickable-entry类即可:

HtmlText(htmlContent = "<span class='clickable-entry'>测试词条1</span> <span class='clickable-entry'>测试词条2</span>")

2. 优化WebView配置(可选但建议)

  • 避免内存泄漏:使用Application Context初始化WebAppInterface,而不是Activity Context
  • 避免重复加载:在update块中判断htmlContent是否变化,再决定是否重新加载内容

修改后的完整HtmlText Composable:

class WebAppInterface(private val context: Context) {
    @JavascriptInterface
    fun showToast(toastMessage: String) {
        Toast.makeText(context, toastMessage, Toast.LENGTH_SHORT).show()
    }
}

@SuppressLint("SetJavaScriptEnabled")
@Composable
fun HtmlText(htmlContent: String) {
    val rightAlignedHtmlContent = """
        <html>
        <head>
            <style>
                body {
                    text-align: right;
                }
                .clickable-entry {
                    color: #1a73e8;
                    text-decoration: underline;
                    cursor: pointer;
                }
            </style>
        </head>
        <body>
            $htmlContent
            <script type="text/javascript">
                document.querySelectorAll('.clickable-entry').forEach(element => {
                    element.addEventListener('click', function() {
                        Android.showToast(this.innerText);
                    });
                });
            </script>
        </body>
        </html>
    """.trimIndent()

    Column(
        modifier = Modifier
            .fillMaxSize()
            .background(color = Color.Transparent, shape = RoundedCornerShape(16.dp))
            .border(width = 1.dp, color = Color.Transparent),
    ) {
        AndroidView(
            modifier = Modifier
                .fillMaxSize()
                .padding(8.dp)
                .background(color = Color.Transparent, shape = RoundedCornerShape(16.dp))
                .border(width = 1.dp, color = Color.Transparent),
            factory = { context ->
                WebView(context).apply {
                    webViewClient = WebViewClient()
                    settings.javaScriptEnabled = true
                    // 使用Application Context避免内存泄漏
                    addJavascriptInterface(WebAppInterface(context.applicationContext), "Android")
                    loadDataWithBaseURL(null, rightAlignedHtmlContent, "text/html", "UTF-8", null)
                }
            },
            update = { webView ->
                // 仅当内容变化时重新加载,避免重复刷新
                val currentContent = webView.title // 或通过其他方式判断内容是否变更
                if (currentContent != htmlContent) {
                    webView.loadDataWithBaseURL(null, rightAlignedHtmlContent, "text/html", "UTF-8", null)
                }
            }
        )
    }
}

关键注意事项

  • 确保@JavascriptInterface注解存在,且方法是public(你的代码已经满足)
  • WebView必须开启JavaScript支持(settings.javaScriptEnabled = true)
  • 如果HTML内容来自网络,需要注意内容安全策略,但本地加载loadDataWithBaseURL不会有此问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 22:14:55