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

Android Kotlin WebView执行JS获取元素坐标后JSON解析失败,如何正确解析为Kotlin变量?

Android Kotlin WebView执行JS获取元素坐标后JSON解析失败,如何正确解析为Kotlin变量?

我来帮你解决这个问题!你遇到的核心问题是WebView.evaluateJavascript()返回的结果字符串被额外包裹了一层双引号,直接解析成JSONObject或者用Klaxon都会失败,因为格式不符合标准JSON要求。

先看你遇到的报错:org.json.JSONException: Value {"x":0,"y":56} of type java.lang.String cannot be converted to JSONObject,其实这个返回的result实际值是"{"x":0,"y":56}"(外层多了一对双引号),这是因为evaluateJavascript会把JS返回的字符串值自动用双引号包裹起来,导致解析失败。

下面是具体的解决方法:

方法一:处理字符串后用原生JSONObject解析

修改你evaluateJavascript的回调代码,先去掉result前后的双引号,再进行解析:

mainWebView.evaluateJavascript(
    "(function() { var element = document.getElementById('full-bleed-container'); var rect = element.getBoundingClientRect(); return JSON.stringify({ x: rect.left, y: rect.top }); })();"
) { result ->
    if (result == "null") {
        Toast.makeText(this, "NULL!", Toast.LENGTH_SHORT).show()
    } else {
        // 去掉前后的双引号,得到标准JSON字符串
        val cleanResult = result.trim('"')
        try {
            val coordinates = JSONObject(cleanResult)
            val x = coordinates.getDouble("x")
            val y = coordinates.getDouble("y")
            Toast.makeText(this, "Coordinates: X: $x, Y: $y", Toast.LENGTH_SHORT).show()
        } catch (e: JSONException) {
            Toast.makeText(this, "解析失败: ${e.message}", Toast.LENGTH_SHORT).show()
        }
    }
}

这个方法的关键是trim('"'),它会把外层多余的双引号去掉,得到符合标准JSON格式的字符串,这样就能正常解析成JSONObject了。

方法二:用Klaxon解析(需先处理字符串)

如果你还是想用Klaxon库,同样需要先清理外层的双引号,再解析:

mainWebView.evaluateJavascript(
    "(function() { var element = document.getElementById('full-bleed-container'); var rect = element.getBoundingClientRect(); return JSON.stringify({ x: rect.left, y: rect.top }); })();"
) { result ->
    if (result == "null") {
        Toast.makeText(this, "NULL!", Toast.LENGTH_SHORT).show()
    } else {
        val cleanResult = result.trim('"')
        // 用Klaxon解析清理后的字符串
        val coordinates = Klaxon().parse<JSONCoordinatesResponse>(cleanResult)
        coordinates?.let {
            Toast.makeText(this, "Coordinates: X: ${it.x}, Y: ${it.y}", Toast.LENGTH_SHORT).show()
        } ?: run {
            Toast.makeText(this, "解析失败!", Toast.LENGTH_SHORT).show()
        }
    }
}

// 注意:坐标是浮点数,所以字段类型用Double而不是Int
data class JSONCoordinatesResponse(val x: Double, val y: Double)

这里要特别注意:YouTube返回的坐标是浮点数(比如y:56.0),所以数据类的字段类型必须用Double,避免类型转换错误。

额外注意事项

  1. 确保目标元素已完全加载:虽然你用了onPageFinished,但YouTube页面是动态渲染的,可能onPageFinished触发时,full-bleed-container元素还没渲染完成。可以修改JS代码,用MutationObserver监听元素是否存在后再返回结果:
"(function() { 
  return new Promise(resolve => {
    const observer = new MutationObserver((mutations, obs) => {
      const element = document.getElementById('full-bleed-container');
      if (element) {
        const rect = element.getBoundingClientRect();
        resolve(JSON.stringify({ x: rect.left, y: rect.top }));
        obs.disconnect();
      }
    });
    observer.observe(document.body, { childList: true, subtree: true });
  });
})();"

这样能确保元素存在后再返回坐标,避免返回null。

  1. WebView设置补充:如果遇到其他加载问题,可以补充以下设置:
mainWebView.settings.allowFileAccess = true
mainWebView.settings.javaScriptCanOpenWindowsAutomatically = false

备注:内容来源于stack exchange,提问作者TechyBenji

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.13 20:18:12