灯火互联
管理员
管理员
  • 注册日期2011-07-27
  • 发帖数41778
  • QQ
  • 火币41290枚
  • 粉丝1086
  • 关注100
  • 终身成就奖
  • 最爱沙发
  • 忠实会员
  • 灌水天才奖
  • 贴图大师奖
  • 原创先锋奖
  • 特殊贡献奖
  • 宣传大使奖
  • 优秀斑竹奖
  • 社区明星
阅读:6538回复:0

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

楼主#
更多 发布于:2012-09-06 14:05

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

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

第一步,WebKit的准备
首先,给与WebKit的javascript的执行许可

[java]
public void onCreate(Bundle icicle) {
  super.onCreate(icicle);
  WebView wv = new WebView(this);
  wv.getSettings().setjavaScriptEnabled(true);//JS利用OK
  setContentView(wv);
}
然后,塞入自己的javascript拦截器
[java]
JsObj jo = new JsObj(this);
wv.addjavascriptinterface(jo, "roid");
第二步,定义自己的javascript拦截器

[java]
class JsObj {
  private Context con;
  
  public JsObj(Context con) {
    this.con = con;
  }
  
  public String gps(String top, String end) {
    LocationManager locman = (LocationManager)  
         con.getSystemService(Context.LOCATION_SERVICE);
    Location loc = locman.getCurrentLocation("gps");
    int lat = (int) (loc.getLatitude() * 1000000);
    int lon = (int) (loc.getLongitude() * 1000000);
    return top + "緯度:" + lat + ", 経度: " + lon + end;
  }
}
第三步,定义一个可运行的html
[html]
<html>
  <head><title>JS calls Android Method</title></head>
  <body>
    <h1>JS on Android</h1>
    <script type="text/javascript">
      document.write(roid.gps("<i>", "</i>"));
    </script>
  </body>
</html>
在这个代码里面,可以用roid.gps的方法调用第二步定义的java函数

最后,全部的代码
[java]
package com.adamrocker.Android.web;
  
import Android.app.Activity;
import Android.content.Context;
import Android.location.Location;
import Android.location.LocationManager;
import Android.os.Bundle;
import Android.webkit.WebView;
  
public class WebkitTest extends Activity {
  /** Called when the activity is first created. */
  @Override
   public void onCreate(Bundle icicle) {
      super.onCreate(icicle);
      WebView wv = new WebView(this);
      wv.getSettings().setjavaScriptEnabled(true);
      JsObj jo = new JsObj(this);
      wv.addjavascriptInterface(jo, "roid");
      setContentView(wv);
      wv.loadUrl("www.atcpu.com");
  }
  
   class JsObj {
      private Context con;
  
      public JsObj(Context con) {
         this.con = con;
      }
  
      public String gps(String top, String end) {
         LocationManager locman = (LocationManager) con
              .getSystemService(Context.LOCATION_SERVICE);
         Location loc = locman.getCurrentLocation("gps");
         int lat = (int) (loc.getLatitude() * 1000000);
         int lon = (int) (loc.getLongitude() * 1000000);
         return top + "緯度:" + lat + ", 経度: " + lon + end;
      }
  }
}
未完
我还想知道为什么,在webview里面定义一个JSObject,就可以连接javascript和后台函数
他们之间是如何通信的?
我稍微调查了一下WebView的底层代码,webview初期化的时候
[java]
/* Initialize private data within the WebCore thread.
  */
private void  [More ...] initialize() {

     /* Initialize our private BrowserFrame class to handle all
      * frame-related functions. We need to create a new view which
   * in turn creates a C level FrameView and attaches it to the frame.
      */
     mBrowserFrame = new BrowserFrame(mContext, this, mCallbackProxy,
             mSettings, mjavascriptInterfaces);
     mjavascriptInterfaces = null;
     // Sync the native settings and also create the WebCore thread handler.
     mSettings.syncSettingsAndCreateHandler(mBrowserFrame);
     // Create the handler and transfer messages for the IconDatabase
     WebIconDatabase.getInstance().createHandler();
     // Create the handler for WebStorage
     WebStorage.getInstance().createHandler();
     // Create the handler for GeolocationPermissions.
     GeolocationPermissions.getInstance().createHandler();
     // The transferMessages call will transfer all pending messages to the
     // WebCore thread handler.
     mEventHub.transferMessages();
     // Send a message back to WebView to tell it that we have set up the
     // WebCore thread.
     if (mWebView != null) {
         Message.obtain(mWebView.mPrivateHandler,
                 WebView.WEBCORE_INITIALIZED_MSG_ID,
                 mNativeClass, 0).sendToTarget();
     }
     }
生成了显示用对象
mBrowserFrame

而此对象的所有操作事件,都会被
mEventHub截获
而mEventHub会将请求发送给真正需要处理的MessageStub。 通过messageName
[java]
Transfer all messages to the newly created webcore thread handler.

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

      mTid = Process.myTid();

      mSavedPriority = Process.getThreadPriority(mTid);

      mHandler = new Handler() {

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

              if (DebugFlags.WEB_VIEW_CORE) {

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

                          || msg.what

                          > VALID_NODE_BOUNDS ? Integer.toString(msg.what)

                          : HandlerDebugString[msg.what

                                  - REQUEST_LABEL])

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

                          + " obj=" + msg.obj);

              }

              switch (msg.what) {

                  case WEBKIT_DRAW:

                      webkitDraw();
作者:nanjingjiangbiao

喜欢0 评分0
游客

返回顶部