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