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

今天調查一個線上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.aiwalls.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

發佈留言