Android WebView Java和JS通信

前言:

Android开发中,经常使用WebView来加载网页,而和WebView进行交互全部通过Java和Js互相调用来完成的。这篇文章就主要学习这块的知识。

本示例中,主要解决以下问题:

  1. Java调用JS
  2. JS调用Java
  3. Java获取JS成员变量(JS没有提供获取该成员变量方法,需要自己注入JS)

另外,除了注入通信对象以外,还可以在JS中调用alert()或者prompt() 方法来传递信息给WebView,在WebChromeClient中拦截获取该信息。

所有代码在 github JavaJSActivity 上。

图例:
JavaJs

示例代码:

Js端:

<script>
var jsVariables = "这个是js成员变量";//要获取这个

function toastShow(msg) {
    //获取注入的Java对象,调用该对象的方法,传入param
    window.injectedObject.toast(msg);
}

/*
java调用js,设置ID为responseBody的内容为content
*/
function contentShow(content){
    var divElement = document.getElementById("responseBody");
    divElement.innerHTML = content;
}
</script>

Java端:

  @Override protected void OnCreate(Bundle savedInstanceState) {
    //避免内存泄露,在Ondestory()回收
    webView = new WebView(getApplicationContext());
    frameLayout.addView(webView);
    initWebView();
  }

  /*
  初始化webView
      第一步:允许Js调用
      第二步:添加Java和Js通信接口
      第三步:编写互相通信代码
  */
 @SuppressLint("JavascriptInterface") private void initWebView() {
    WebSettings settings = webView.getSettings();
    settings.setSupportZoom(false);

    //1. 允许JS调用
    settings.setJavaScriptEnabled(true);

    //2. 设置调用接口
    /*
    参数1:java对象,该类的方法被js通过参数2直接调用
    参数2:js对象。注册到window中,js可通过该对象调用JsObject()里的方法。实现js调用java
    */
    webView.addJavascriptInterface(new JsObject(), "injectedObject");

    //js中调用alert()方法必须要设置这个
    webView.setWebChromeClient(new WebChromeClient() {
               @Override public boolean onJsAlert(WebView view, String url, String message, JsResult result) {

                showToast(message);
                result.confirm();//必须要调这一句
                return true;

                //return super.onJsAlert(view, url, message, result);
            }

            @Override public boolean onJsPrompt(WebView view, String url, String message, String defaultValue,
                    JsPromptResult result) {

                showToast(message);
                result.confirm();
                return true;

                //return super.onJsPrompt(view, url, message, defaultValue, result);
            }
        });
    });

    webView.setWebViewClient(new WebViewClient() {
    @Override public void onPageFinished(WebView view, String url) {
        super.onPageFinished(view, url);

        //java调用JS
        webView.loadUrl("javascript:contentShow('哈哈哈哈哈哈,第一次进来')");
      }
    });

    //加载本地assets文件
    webView.loadUrl("file:///android_asset/page.html");
  }

 //通信对象
 public class JsObject {
    @JavascriptInterface public void toast(final String msg) {
      runOnUiThread(new Runnable() {
        @Override public void run() {
           Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();
        }
      });


    @JavascriptInterface 
    //Java获取JS成员变量回调
    public void  onJavaGetVariables(String jsVariables) {
          toast(jsVariables);
    }
 }

  //Button点击事件,注入JS方法,获取JS成员变量,再通过Java返回来
  public void getJSVariables(View view) {
    //Java调用JS方法
    webView.loadUrl("javascript:(function getVariables(){"
        + "  return window.injectedObject.onJavaGetVariables(jsVariables);"
        + "})()");
  }

遇到的错误处理:

全都是自己遇到的,再次感谢技术小黑屋,解决方法有些不一样。

Uncaught TypeError: object is not a function.

//解决方法: id和 onclick时的方法名不能一样
<input type="button" value="展示标准提示信息" id="toast" onclick="toastShow('标准提示信息');"/>

更多请看: stackoverflow

Uncaught ReferenceError: functionName is not define

  //类必须是public的
  public class JsObject {

    //必须要添加@JavascriptInterface注解
    @JavascriptInterface  
    //方法必须是public的
    public void error(final String msg) {
      runOnUiThread(new Runnable() {
        @Override  
        public void run() {
          //....
        }
      });
    }

官方文档:If you’ve set your targetSdkVersion to 17 or higher, you must add the @JavascriptInterface annotation to any method that you want available to your JavaScript (the method must also be public).

CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

 @JavascriptInterface  
 public void error(final String msg) {
      //使用runOnUiThread()方法保证在主线程运行。
      runOnUiThread(new Runnable() {
        @Override  
        public void run() {
          //...
        }
      });

官方文档:JavaScript interacts with Java object on a private, background thread of this WebView. Care is therefore required to maintain thread safety.

All WebView methods must be called on the same thread.

    //使用webView.post()方法让任务执行在webView所在thread上
    webView.post(new Runnable() {
        @Override  
        public void run() {
        //传入字符串,需要加单引号
        String s = "javascript:contentShow('" + content + "')";
        webView.loadUrl(s);
        }
    });




参考:
技术小黑屋: Java和JavaScript交互
API: addJavascriptInterface()
官方文档: Building Web Apps in WebView

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

baiiu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值