Android WebViewJSBridge分析

Android WebViewJSBridge分析

WebViewJavascriptBridge的github地址

这种方法采用js注入的方式来实现webView与h5的交互
相关文件的UML图


image

Native相关操作

  • Activity中new WebViewJavascriptBridge()对象 bridge

  • 在WebView加载成功之后 onPageFinish()方法中加载本地js代码

  • 在WebView对象上addJavascriptInterface(Object object, String name),This method can be used to allow JavaScript to control the host application. 在本地js文件中可以通过该name来,调用Native方法,调用的方法必须由@JavascriptInterface 注解

      mWebView.addJavascriptInterface(this, "_WebViewJavascriptBridge");  
    
本地js代码实现的功能
  • 在当前window上添加WebViewJavascriptBridge对象
  • 在当前document对象上添加一个event, 将该WebViewJavascriptBridge添加到event中,通过document分发这个event
  • 在html加载的js文件中,监听该event。收到该event消息之后,获取event中WebViewJavascriptBridge对象,进行初始化, 给WebViewJavascriptBridge._messageHandler赋值。

现在H5页面获取WebViewJavascriptBridge对象,可以进行交互啦!

H5发送消息到Native

bridge就是H5页面获取的WebViewJavascriptBridge对象

bridge.callHandler("handler1","gift for handler1",function(responseData){
        console.log("got handler1 response:"+responseData);
    });

Native处理H5发来的消息

  • native本地的js代码

      function callHandler(handlerName, data, responseCallback) {
          _doSend({ handlerName:handlerName, data:data }, responseCallback)
      }
      function _doSend(message, responseCallback) {
          if (responseCallback) {
              var callbackId = 'cb_'+(uniqueId++)+'_'+new Date().getTime();
              responseCallbacks[callbackId] = responseCallback;
              message['callbackId'] = callbackId;
              }
              console.log("sending:"+JSON.stringify(message));
          //调用Native方法
          _WebViewJavascriptBridge._handleMessageFromJs(JSON.stringify(message.data)||null,message.responseId||null,
              message.responseData||null,message.callbackId||null,message.handlerName||null);
    
      }
    
  • native代码处理消息
    _handleMessageFromJs方法负责找到注册该hanlderName的WVJBHandler,把h5发来的信息回调回Activity,Activity做相应的处理。</br>

      @JavascriptInterface
      public void _handleMessageFromJs(final String data, String responseId,
                                       String responseData, String callbackId, String handlerName){
          if (null!=responseId) {
              WVJBResponseCallback responseCallback = _responseCallbacks.get(responseId);
              responseCallback.callback(responseData);
              _responseCallbacks.remove(responseId);
          } else {
              WVJBResponseCallback responseCallback = null;
              if (null!=callbackId) {
                  responseCallback=new CallbackJs(callbackId);
              }
              final WVJBHandler handler;
              if (null!=handlerName) {
                  handler = _messageHandlers.get(handlerName);
                  if (null==handler) {
                      Log.e("test","WVJB Warning: No handler for "+handlerName);
                      return ;
                  }
              } else {
                  handler = _messageHandler;
              }
              try {
                  final WVJBResponseCallback finalResponseCallback = responseCallback;
                  mContext.runOnUiThread(new Runnable(){
                      @Override
                      public void run() {
                          //回调给Activity处理
                          handler.handle(data, finalResponseCallback);
                      }
                  });
              }catch (Exception exception) {
                  Log.e("test","WebViewJavascriptBridge: WARNING: java handler threw. "+exception.getMessage());
              }
          }
      }
    

Native发送消息到H5

  • Activity中WebViewJavascriptBridge对象bridge,这个对象和window.WebViewJavascriptBridge不是同一个。

      bridge.callHandler("gotoMarker","1");
    

    WebViewJavascriptBridge.java

      public void callHandler(String handlerName, String data) {
       callHandler(handlerName, data,null);
      }
    
      public void callHandler(String handlerName, String data, WVJBResponseCallback responseCallback){
       _sendData(data, responseCallback,handlerName);
      }
      
      private void _sendData(String data, WVJBResponseCallback responseCallback, String handlerName){
      Map<String, String> message=new HashMap<String,String>();
      message.put("data",data);
      if (null!=responseCallback) {
          String callbackId = "java_cb_"+ (++_uniqueId);
          _responseCallbacks.put(callbackId,responseCallback);
          message.put("callbackId",callbackId);
      }
      if (null!=handlerName) {
          message.put("handlerName", handlerName);
      }
      _dispatchMessage(message);
      }
    
      private void _dispatchMessage(Map<String, String> message){
      String messageJSON = new JSONObject(message).toString();
      //调用WebViewJavascriptBridge.js的方法
      final String javascriptCommand=String.format("javascript:WebViewJavascriptBridge._handleMessageFromJava('%s');",doubleEscapeString(messageJSON));
      mContext.runOnUiThread(new Runnable(){
          @Override
          public void run() {
              mWebView.loadUrl(javascriptCommand);    
          }
      });
      }
    

H5处理Native发来的消息

Native的js代码处理,找到H5代码注册的那个Handler回调方法,回调回去,即可处理消息。</br>

WebViewJavascriptBridge.js

function _dispatchMessageFromJava(messageJSON) {
        var message = JSON.parse(messageJSON);
        var messageHandler;
        
        if (message.responseId) {
            var responseCallback = responseCallbacks[message.responseId];
            if (!responseCallback) { return; }
            responseCallback(message.responseData);
            delete responseCallbacks[message.responseId]
        } else {
            var responseCallback;
            if (message.callbackId) {
                var callbackResponseId = message.callbackId;
                responseCallback = function(responseData) {
                    _doSend({ responseId:callbackResponseId, responseData:responseData })
                }
            }
            
            var handler = WebViewJavascriptBridge._messageHandler;
            if (message.handlerName) {
                handler = messageHandlers[message.handlerName]
            }
            try {
                handler(message.data, responseCallback)
            } catch(exception) {
                if (typeof console != 'undefined') {
                    console.log("WebViewJavascriptBridge: WARNING: javascript handler threw."+ exception)
                }
            }
        }
}

html中方法

bridge.registerHandler("showAlert", function(data) { console.log("alert:"+data); });
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,108评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,699评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,812评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,236评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,583评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,739评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,957评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,704评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,447评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,643评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,133评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,486评论 3 256
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,151评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,889评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,782评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,681评论 2 272