调查一个线上Bug,发现是WebView中的一小段javascript,会直接调用到后台APK的一个Java事件,最后导致java中nullpointexception。
感兴趣的是,WebView中的javascript如何调用APK中的java方法。
一个例子:
通过JS取得Android的GPS数据
第一步,WebKit的准备
首先,给与WebKit的javascript的执行许可
复制代码
然后,塞入自己的javascript拦截器
复制代码
第二步,定义自己的javascript拦截器
复制代码
第三步,定义一个可运行的html
复制代码
在这个代码里面,可以用roid.gps的方法调用第二步定义的java函数
最后,全部的代码
复制代码
未完
我还想知道为什么,在webview里面定义一个JSObject,就可以连接javascript和后台函数
他们之间是如何通信的?
我稍微调查了一下WebView的底层代码,webview初期化的时候
复制代码
生成了显示用对象
mBrowserFrame
而此对象的所有操作事件,都会被
mEventHub截获而mEventHub会将请求发送给真正需要处理的MessageStub。 通过messageName
复制代码
所以你要问我他们是怎么通信的
我只能说是线程间通信。
感兴趣的是,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);
- }
- JsObj jo = new JsObj(this);
- wv.addJavascriptInterface(jo, "roid");
- 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>
- <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>
最后,全部的代码
- 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。 通过messageName
- 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();
我只能说是线程间通信。