WebView.evaluateJavascript()为何会移除转义字符?
最近在做Android WebView与原生交互时,碰到了一个嵌套JSON字符串传递的坑——明明调试时JSON格式完全正确,可一通过evaluateJavascript传给WebView,内部的转义引号就莫名消失了,直接导致前端执行JSON.parse时触发解析错误。下面把问题重现、原因分析和解决方法整理出来:
问题重现
1. 一级JSON的正常场景
如果是简单的一级JSON,序列化后传递给WebView完全没问题:
JSONObject object = new JSONObject(); object.put("key1", "val1"); object.put("key2", "val2"); String myValue = object.toString();
调用evaluateJavascript输出:
webView.evaluateJavascript("console.log('" + myValue + "')", null);
控制台能正确输出:
{"key1": "val1", "key2": "val2"}
2. 嵌套JSON的异常场景
但如果JSON里包含嵌套的子对象,问题就来了。先看序列化代码:
JSONObject object = new JSONObject(); object.put("key1", "val1"); JSONObject innerObject = new JSONObject(); innerObject.put("key3","val3"); object.put("key2", innerObject); String myValue = object.toString();
同样调用evaluateJavascript后,控制台输出的内容不符合预期:
{"key1":"val1", "key2": "{"key3": "val3"}"}
而我们期望的正确格式应该是:
{"key1":"val1", "key2": "{\"key3\": \"val3\"}"}
这种错误格式下,前端执行JSON.parse必然会报错,因为内部的双引号没有被正确转义。
调试时的矛盾点
我特意通过调试器检查了传入evaluateJavascript前的myValue运行时值,格式是完全正确的:
"{\"key1\":\"val1\", \"key2\": \"{\\\"key3\\\": \\\"val3\\\"}\"}"
那为什么一调用evaluateJavascript,这些显式的转义符号就被移除了?
原因分析
其实核心问题在于字符串转义的层级消耗:
Java中的字符串转义符(\)在拼接成JavaScript代码字符串时,会被JavaScript引擎再解析一次。比如Java里的\",在拼接成JS的字符串字面量后,JS引擎会把它当成一个普通的双引号,而不是我们需要的转义引号。相当于原本的转义被“消耗”了一层,最终传到WebView里的JSON就丢失了必要的转义。
解决方法
要避免转义被消耗,我们需要在传递给evaluateJavascript之前,把Java字符串中的转义字符再转义一次——也就是把单个的\替换成两个\\。这样当JS引擎解析时,会去掉一层转义,最终正好保留我们需要的\"。
具体代码如下:
// 对转义字符进行二次转义 myValue = myValue.replace("\\", "\\\\");
之后再调用evaluateJavascript:
webView.evaluateJavascript("console.log('" + myValue + "')", null);
这样控制台就能输出正确的带转义的JSON字符串,前端执行JSON.parse也能正常解析了。
内容的提问来源于stack exchange,提问作者George V.M.

