Android中Java和JavaScript交互

Android提供了一个很强大的WebView控件用来处理Web网页,而在网页中,JavaScript又是一个很举足轻重的脚本。本文将介绍如何实现Java代码和Javascript代码的相互调用。javascript

 

如何实现

实现Java和js交互十分便捷。一般只须要如下几步。html

 

  • WebView开启JavaScript脚本执行
  • WebView设置供JavaScript调用的交互接口。
  • 客户端和网页端编写调用对方的代码。

本例代码

为了便于讲解,先贴出所有代码前端

Java代码java

public class MainActivity extends Activity {
  private static final String LOGTAG = "MainActivity";
  @SuppressLint("JavascriptInterface")
  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      final WebView myWebView = (WebView) findViewById(R.id.myWebView);
      WebSettings settings = myWebView.getSettings();
      settings.setJavaScriptEnabled(true);
      myWebView.addJavascriptInterface(new JsInteration(), "control");
      myWebView.setWebChromeClient(new WebChromeClient() {});
      myWebView.setWebViewClient(new WebViewClient() {

          @Override
          public void onPageFinished(WebView view, String url) {
              super.onPageFinished(view, url);
              testMethod(myWebView);
          }

      });
      myWebView.loadUrl("file:///android_asset/js_java_interaction.html");
  }

  private void testMethod(WebView webView) {
      String call = "javascript:sayHello()";

      call = "javascript:alertMessage(\"" + "content" + "\")";

      call = "javascript:toastMessage(\"" + "content" + "\")";

      call = "javascript:sumToJava(1,2)";
      webView.loadUrl(call);

  }

  public class JsInteration {

      @JavascriptInterface
      public void toastMessage(String message) {
          Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show();
      }

      @JavascriptInterface
      public void onSumResult(int result) {
          Log.i(LOGTAG, "onSumResult result=" + result);
      }
  }

}

前端网页代码android

 1 <html>
 2 <script type="text/javascript">
 3     function sayHello() {
 4         alert("Hello")
 5     }
 6 
 7     function alertMessage(message) {
 8         alert(message)
 9     }
10 
11     function toastMessage(message) {
12         window.control.toastMessage(message)
13     }
14 
15     function sumToJava(number1, number2){
16        window.control.onSumResult(number1 + number2)
17     }
18 </script>
19 Java-Javascript Interaction In Android
20 </html>

调用示例

js调用Java

调用格式为window.jsInterfaceName.methodName(parameterValues) 此例中咱们使用的是control做为注入接口名称。web

1 function toastMessage(message) {
2   window.control.toastMessage(message)
3 }
4 
5 function sumToJava(number1, number2){
6    window.control.onSumResult(number1 + number2)
7 }

Java调用JS

webView调用js的基本格式为webView.loadUrl(“javascript:methodName(parameterValues)”)json

调用js无参无返回值函数

String call = "javascript:sayHello()";
webView.loadUrl(call);

调用js有参无返回值函数

注意对于字符串做为参数值须要进行转义双引号。安全

String call = "javascript:alertMessage(\"" + "content" + "\")";
webView.loadUrl(call);

  

调用js有参数有返回值的函数

Android在4.4以前并无提供直接调用js函数并获取值的方法,因此在此以前,经常使用的思路是 java调用js方法,js方法执行完毕,再次调用java代码将值返回。ide

1.Java调用js代码函数

String call = "javascript:sumToJava(1,2)";
webView.loadUrl(call);

2.js函数处理,并将结果经过调用java方法返回

function sumToJava(number1, number2){
       window.control.onSumResult(number1 + number2)
}

3.Java在回调方法中获取js函数返回值

@JavascriptInterface
public void onSumResult(int result) {
  Log.i(LOGTAG, "onSumResult result=" + result);
}

4.4处理

Android 4.4以后使用evaluateJavascript便可。这里展现一个简单的交互示例 具备返回值的js方法

function getGreetings() {
      return 1;
}

  java代码时用evaluateJavascript方法调用

private void testEvaluateJavascript(WebView webView) {
  webView.evaluateJavascript("getGreetings()", new ValueCallback<String>() {

  @Override
  public void onReceiveValue(String value) {
      Log.i(LOGTAG, "onReceiveValue value=" + value);
  }});
}

  输出结果

I/MainActivity( 1432): onReceiveValue value=1

  

注意

 

  • 上面限定告终果返回结果为String,对于简单的类型会尝试转换成字符串返回,对于复杂的数据类型,建议以字符串形式的json返回。
  • evaluateJavascript方法必须在UI线程(主线程)调用,所以onReceiveValue也执行在主线程。

 

疑问解答

Alert没法弹出

你应该是没有设置WebChromeClient,按照如下代码设置

myWebView.setWebChromeClient(new WebChromeClient() {});

  

Uncaught ReferenceError: functionName is not defined

问题出现缘由,网页的js代码没有加载完成,就调用了js方法。解决方法是在网页加载完成以后调用js方法

myWebView.setWebViewClient(new WebViewClient() {

  @Override
  public void onPageFinished(WebView view, String url) {
      super.onPageFinished(view, url);
      //在这里执行你想调用的js函数
  }

});

  

Uncaught TypeError: Object [object Object] has no method

安全限制问题

若是只在4.2版本以上的机器出问题,那么就是系统处于安全限制的问题了。Android文档这样说的

Caution: If you’ve set your targetSdkVersion to 17 or higher, you must add the @JavascriptInterface annotation to any method that you want available your web page code (the method must also be public). If you do not provide the annotation, then the method will not accessible by your web page when running on Android 4.2 or higher.

  中文大意为

警告:若是你的程序目标平台是17或者是更高,你必需要在暴露给网页可调用的方法(这个方法必须是公开的)加上@JavascriptInterface注释。若是你不这样作的话,在4.2以之后的平台上,网页没法访问到你的方法。

  

两种解决方法

 

  • 将targetSdkVersion设置成17或更高,引入@JavascriptInterface注释
  • 本身建立一个注释接口名字为@JavascriptInterface,而后将其引入。注意这个接口不能混淆。

 

注,建立@JavascriptInterface代码

public @interface JavascriptInterface {

}

  

代码混淆问题

若是在没有混淆的版本运行正常,在混淆后的版本的代码运行错误,并提示Uncaught TypeError: Object [object Object] has no method,那就是你没有作混淆例外处理。 在混淆文件加入相似这样的代码

-keep class com.example.javajsinteractiondemo$JsInteration {
    *;
}

  

All WebView methods must be called on the same thread

过滤日志曾发现过这个问题。

E/StrictMode( 1546): java.lang.Throwable: A WebView method was called on thread 'JavaBridge'. All WebView methods must be called on the same thread. (Expected Looper Looper (main, tid 1) {528712d4} called on Looper (JavaBridge, tid 121) {52b6678c}, FYI main Looper is Looper (main, tid 1) {528712d4})
E/StrictMode( 1546):   at android.webkit.WebView.checkThread(WebView.java:2063)
E/StrictMode( 1546):   at android.webkit.WebView.loadUrl(WebView.java:794)
E/StrictMode( 1546):   at com.xxx.xxxx.xxxx.xxxx.xxxxxxx$JavaScriptInterface.onCanGoBackResult(xxxx.java:96)
E/StrictMode( 1546):   at com.android.org.chromium.base.SystemMessageHandler.nativeDoRunLoopOnce(Native Method)
E/StrictMode( 1546):   at com.android.org.chromium.base.SystemMessageHandler.handleMessage(SystemMessageHandler.java:27)
E/StrictMode( 1546):   at android.os.Handler.dispatchMessage(Handler.java:102)
E/StrictMode( 1546):   at android.os.Looper.loop(Looper.java:136)
E/StrictMode( 1546):   at android.os.HandlerThread.run(HandlerThread.java:61)

  在js调用后的Java回调线程并非主线程。如打印日志可验证

ThreadInfo=Thread[WebViewCoreThread,5,main]

  解决上述的异常,将webview操做放在主线程中便可。

webView.post(new Runnable() {
    @Override
    public void run() {
        webView.loadUrl(YOUR_URL).
    }
});
相关文章
相关标签/搜索