场景:Android的Webview中,javascript怎么调用java方法

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

今天调查一个线上Bug,发现是WebView中的一小段javascript,会直接调用到后台APK的一个Java事件,最后导致java中nullpointexception。

感兴趣的是,WebView中的javascript如何调用APK中的java方法。

一个例子:

通过JS取得Android的GPS数据

第一步,WebKit的准备

首先,给与WebKit的javascript的执行许可

public void onCreate(Bundle icicle) {
super.onCreate(icicle);
WebView wv = new WebView(this);
wv.getSettings().setJavaScriptEnabled(true);//JS利用OK
setContentView(wv);
}

然后,塞入自己的javascript拦截器JsObj jo = new JsObj(this);

wv.addJavascriptInterface(jo, "roid");

第二步,定义自己的javascript拦截器

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

JS calls Android Method


JS on Android

document.write(roid.gps("", ""));

在这个代码里面,可以用roid.gps的方法调用第二步定义的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("http://www.adamrocker.com/android/js2android.html");
}
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初期化的时候

/* 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。 通过messageNameTransfer 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();

所以你要问我他们是怎么通信的

我只能说是线程间通信。