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,避免类型转换错误。
额外注意事项
- 确保目标元素已完全加载:虽然你用了
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。
- WebView设置补充:如果遇到其他加载问题,可以补充以下设置:
mainWebView.settings.allowFileAccess = true mainWebView.settings.javaScriptCanOpenWindowsAutomatically = false
备注:内容来源于stack exchange,提问作者TechyBenji
相关产品推荐
相关产品推荐

