Android的Webview中,javascript如何调用java方法

调查一个线上Bug,发现是WebView中的一小段javascript,会直接调用到后台APK的一个Java事件,最后导致java中nullpointexception。
感兴趣的是,WebView中的javascript如何调用APK中的java方法。

一个例子:
        通过JS取得Android的GPS数据

第一步,WebKit的准备
首先,给与WebKit的javascript的执行许可
  1. public void onCreate(Bundle icicle) {
  2.   super.onCreate(icicle);
  3.   WebView wv = new WebView(this);
  4.   wv.getSettings().setJavaScriptEnabled(true);//JS利用OK
  5.   setContentView(wv);
  6. }
复制代码
然后,塞入自己的javascript拦截器
  1. JsObj jo = new JsObj(this);
  2. wv.addJavascriptInterface(jo, "roid");
复制代码
第二步,定义自己的javascript拦截器
  1. class JsObj {
  2.   private Context con;

  3.   public JsObj(Context con) {
  4.     this.con = con;
  5.   }

  6.   public String gps(String top, String end) {
  7.     LocationManager locman = (LocationManager) 
  8.          con.getSystemService(Context.LOCATION_SERVICE);
  9.     Location loc = locman.getCurrentLocation("gps");
  10.     int lat = (int) (loc.getLatitude() * 1000000);
  11.     int lon = (int) (loc.getLongitude() * 1000000);
  12.     return top + "緯度:" + lat + ", 経度: " + lon + end;
  13.   }
  14. }
复制代码
第三步,定义一个可运行的html
  1. <html>
  2.   <head><title>JS calls Android Method</title></head>
  3.   <body>
  4.     <h1>JS on Android</h1>
  5.     <script type="text/javascript">
  6.       document.write(roid.gps("<i>", "</i>"));
  7.     </script>
  8.   </body>
  9. </html>
复制代码
在这个代码里面,可以用roid.gps的方法调用第二步定义的java函数

最后,全部的代码
  1. package com.adamrocker.android.web;

  2. import android.app.Activity;
  3. import android.content.Context;
  4. import android.location.Location;
  5. import android.location.LocationManager;
  6. import android.os.Bundle;
  7. import android.webkit.WebView;

  8. public class WebkitTest extends Activity {
  9.   /** Called when the activity is first created. */
  10.   @Override
  11.    public void onCreate(Bundle icicle) {
  12.       super.onCreate(icicle);
  13.       WebView wv = new WebView(this);
  14.       wv.getSettings().setJavaScriptEnabled(true);
  15.       JsObj jo = new JsObj(this);
  16.       wv.addJavascriptInterface(jo, "roid");
  17.       setContentView(wv);
  18.       wv.loadUrl("http://www.adamrocker.com/android/js2android.html");
  19.   }

  20.    class JsObj {
  21.       private Context con;

  22.       public JsObj(Context con) {
  23.          this.con = con;
  24.       }

  25.       public String gps(String top, String end) {
  26.          LocationManager locman = (LocationManager) con
  27.               .getSystemService(Context.LOCATION_SERVICE);
  28.          Location loc = locman.getCurrentLocation("gps");
  29.          int lat = (int) (loc.getLatitude() * 1000000);
  30.          int lon = (int) (loc.getLongitude() * 1000000);
  31.          return top + "緯度:" + lat + ", 経度: " + lon + end;
  32.       }
  33.   }
  34. }
复制代码
未完
我还想知道为什么,在webview里面定义一个JSObject,就可以连接javascript和后台函数
他们之间是如何通信的?
我稍微调查了一下WebView的底层代码,webview初期化的时候
  1. /* Initialize private data within the WebCore thread.
  2.   */
  3. private void  [More ...] initialize() {

  4.      /* Initialize our private BrowserFrame class to handle all
  5.       * frame-related functions. We need to create a new view which
  6.    * in turn creates a C level FrameView and attaches it to the frame.
  7.       */
  8.      mBrowserFrame = new BrowserFrame(mContext, this, mCallbackProxy,
  9.              mSettings, mJavascriptInterfaces);
  10.      mJavascriptInterfaces = null;
  11.      // Sync the native settings and also create the WebCore thread handler.
  12.      mSettings.syncSettingsAndCreateHandler(mBrowserFrame);
  13.      // Create the handler and transfer messages for the IconDatabase
  14.      WebIconDatabase.getInstance().createHandler();
  15.      // Create the handler for WebStorage
  16.      WebStorage.getInstance().createHandler();
  17.      // Create the handler for GeolocationPermissions.
  18.      GeolocationPermissions.getInstance().createHandler();
  19.      // The transferMessages call will transfer all pending messages to the
  20.      // WebCore thread handler.
  21.      mEventHub.transferMessages();
  22.      // Send a message back to WebView to tell it that we have set up the
  23.      // WebCore thread.
  24.      if (mWebView != null) {
  25.          Message.obtain(mWebView.mPrivateHandler,
  26.                  WebView.WEBCORE_INITIALIZED_MSG_ID,
  27.                  mNativeClass, 0).sendToTarget();
  28.      }
  29.      }
复制代码
生成了显示用对象
mBrowserFrame
而此对象的所有操作事件,都会被
mEventHub截获而mEventHub会将请求发送给真正需要处理的MessageStub。 通过messageName
  1. Transfer all messages to the newly created webcore thread handler.

  2.   private void  [More ...] transferMessages() {

  3.       mTid = Process.myTid();

  4.       mSavedPriority = Process.getThreadPriority(mTid);

  5.       mHandler = new Handler() {

  6.           @Override
  7.           public void  [More ...] handleMessage(Message msg) {

  8.               if (DebugFlags.WEB_VIEW_CORE) {

  9.                   Log.v(LOGTAG, (msg.what < REQUEST_LABEL

  10.                           || msg.what

  11.                           > VALID_NODE_BOUNDS ? Integer.toString(msg.what)

  12.                           : HandlerDebugString[msg.what

  13.                                   - REQUEST_LABEL])

  14.                           + " arg1=" + msg.arg1 + " arg2=" + msg.arg2

  15.                           + " obj=" + msg.obj);

  16.               }

  17.               switch (msg.what) {

  18.                   case WEBKIT_DRAW:

  19.                       webkitDraw();
复制代码
所以你要问我他们是怎么通信的
我只能说是线程间通信。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值