在webview中调java代码

很多时候需要在原生App中嵌入Webview,同时在Webview中处理一些事件的时候,js可能不能完全满足需求,这时候就需要通过js来调用 java的代码。

原生支持的实现

使用js调用java代码,其实是Android原生支持的,可以看这里的官方文档(翻墙) 。Webview提供了一层从从 js代码到java原生代码的映射。

定义接口:

public class WebAppInterface {
    Context mContext;

    /** Instantiate the interface and set the context */
    WebAppInterface(Context c) {
        mContext = c;
    }

    /** Show a toast from the web page */
    @JavascriptInterface
    public void showToast(String toast) {
        Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
    }
}

定义js-java映射:

WebView webView = (WebView) findViewById(R.id.webview);
webView.addJavascriptInterface(new WebAppInterface(this), "Android");

在js中调用代码:

<input type="button" value="Say hello" onClick="showAndroidToast('Hello Android!')" / >

<script type="text/javascript" >
    function showAndroidToast(toast) {
        Android.showToast(toast);
    }
</script >

其他实现

上面提供的原生做法在Android的某些版本上是有问题的,另外还存在一些安全问题。在PhoneGap的代码中提供了一种实现思路, 它自己实现了js-java的映射。具体是在webview中发起一个js的事件(js代码),然后再WebChromeClient(原生代码)中处 理这个事件。

定义接口:

public class WebAppInterface {
    Context mContext;

    /** Instantiate the interface and set the context */
    WebAppInterface(Context c) {
        mContext = c;
    }

    /** Show a toast from the web page */
    public void showToast(String toast) {
        Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
    }
}

通过拦截js事件,实现js-java的映射:

final class MyWebChromeClient extends WebChromeClient {
      WebAppInterface wai;
      
      MyWebChromeClient(Context ctx){
        wai = new WebAppInterface(ctx);
      }
      
     	public boolean onJsPrompt(WebView view, String url, String message, String value, JsPromptResult result){
        if("toast".equals(message)){
          wai.showToast(value);
        }
        
        return true;
      }
}

 webview.getSettings().setJavaScriptEnabled(true);
 webview.setWebChromeClient(new MyWebChromeClient(activity));

在js中调用代码:

  <script type="text/javascript">
  
  function showToast(msg) {
      prompt("toast", msg);
  }
  
  </script>  
  
  <a onClick="showToast('click')"> SimpleEvent</a>

上面代码的实现思路是这样的,js代码中的showToast方法会调用 prompt 函数,并且传递了两个参数(其实prompt是js中的一个方法 ,调用这个方法之后会显示一个包含输入框的对话框,第一个参数是对话框的消息,第二个参数是对话框中输入框的内容)。这个js事件 会被自己实现的 MyWebChromeClient 捕获,然后判断消息是不是”toast”,如果是就调用 WebAppInterface 的 showToast 方法。

对于这个实现,需要小心的定义prompt函数的第一个参数,避免不小拦截到了非自己定义的消息。

PS:由于Android原生实现的一些瑕疵,所以在友盟的统计组件中得实现是采用第二种方式。

nTop 30 December 2014
blog comments powered by Disqus