之前在『Android WebView 和 JavaScript 交互』一文中留了一个坑没填,就是当 Android 调用 JavaScript 获取返回值时,返回值是字符串与否也会有不同的情况。

有人可能就有疑惑了,因为文章也同样提到,返回值本身就被限定为 String 类型。

没错,evaluateJavascript() 方法中的 ValueCallback 本身就做了泛型的限定:

@Widget
public class WebView extends AbsoluteLayout implements ViewTreeObserver.OnGlobalFocusChangeListener, ViewGroup.OnHierarchyChangeListener, ViewDebug.HierarchyHandler {
    ...
    public void evaluateJavascript(@NonNull String script, @Nullable ValueCallback<String> resultCallback) {
        checkThread();
        mProvider.evaluateJavaScript(script, resultCallback);
    }
}

那么,假如返回值不为字符串时,会返回什么呢?我们可以动手尝试一下。

比如同样是『Android WebView 和 JavaScript 交互』一文中的例子:

<html>
  <script type="text/javascript">
    function sum(m, n) {
      return m + n
    }
  </script>
  ...
</html>
class WebActivity : AppCompatActivity() {
    ...
    private fun checkInt() {
        webView.evaluateJavascript("sum(3, 2)") { result ->
            Log.d(TAG, result)  // Log: 5
        }
    }
}

我们用 Log 打印出来是 5,记住它不是数字 5,而是一个字符串,即 result = "5"

再来看看布尔类型:

<html>
  <script type="text/javascript">
    function checkBoolean() {
      return true
    }
  </script>
  ...
</html>
class WebActivity : AppCompatActivity() {
    ...
    private fun checkBoolean() {
        webView.evaluateJavascript("checkBoolean()") { result ->
            Log.e(TAG, result)  // Log: true
        }
    }
}

我们用 Log 打印出来是 true,记住它不是布尔值 true,而是一个字符串,即 result = "true"

接下来看看对象,用之前在『Android 获取 WebView 选区位置』也有类似的例子:

<html>
  <script type="text/javascript">
    function checkObj() {
      var json = {};
      json.name = "json";
      return json
    }
  </script>
  ...
</html>
class WebActivity : AppCompatActivity() {
    ...
    private fun checkObj() {
        webView.evaluateJavascript("checkObj()") { result ->
            Log.e(TAG, result)  // Log: {"name":"json"}
        }
    }
}

我们用 Log 打印出来是 {"name":"json"},记住它不是 JSON 对象,而是一个字符串,即 result = "{\"name\":\"json\"}"

最后,我们看看字符串类型:

<html>
  <script type="text/javascript">
    function sayHi() {
        return "Hi"
    }
  </script>
  ...
</html>
class WebActivity : AppCompatActivity() {
    ...
    private fun checkObj() {
        webView.evaluateJavascript("sayHi()") { result ->
            Log.e(TAG, result)  // Log: "Hi"
        }
    }
}

我们用 Log 打印出来是 "Hi",而不是 Hi,即 result = "\"Hi\""

发现没有,当 JavaScript 返回值为字符串时,Android 端会在该字符串前后带上双引号 ",而当返回值为非字符串时,则会直接转为正常的字符串返回。

这样设计的用意也许是 ValueCallback 的泛型指定为 String 后能够更好的区分返回值的类型,但无疑会给使用者造成使用上的麻烦,所以使用时应多加注意。