JsBridge交互原理以及二次开发

本文深入探讨了JsBridge的工作原理,包括JS如何与原生应用交互,以及原生调用Web的多种方式。文章进一步阐述了JsBridge的二次开发,旨在解决原有交互过程中的问题,如减少通信次数、增强兼容性和统一消息处理,以提高效率和可维护性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

JsBridge原理以及二次开发

1丶JsBridge原理

1.1丶JS交互的简单使用

  • 🏷原生方式

    • Native调用Web:

      方式1:Android4.2以前

       webView.loadUrl(jsMethod);
      

      方式2:Android4.2以后:新增

       webView.evaluateJavascript(jsMethod, new ValueCallback<String>() {
                  @Override
                  public void onReceiveValue(String s) {
                      Log.d(TAG, "nativeCallH5ByPrimary2  onReceiveValue: "+s);
                  }
              });
      

      两种方式对比:

      调用方式版本支持是否刷新页面是否存在回调是否可获取常量信息
      loadUrlAndroid各版本
      evaluateJavascriptAndroid4.2及以上
    • Web调用Native:Native提供JavaScript交互的对象

      **方式1:**调用Native挂载在window上的对象进行调用

      Native添加JavaScript

      webView.addJavascriptInterface(new JSHelper(), "jsHelper");
      

      web调用Native方法

      window.jsHelper.webCallNativeFunc();
      

      方式2:Web端调用location.href的方式调用(需要Native进行拦截相应的url进行处理)**

      location.href='xxxxx'
      

      方式3:Web端创建iframe标签,通过iframe.src方式调用(需要Native进行拦截相应的url进行处理)**

      iframe.src='xxxxx'
      

      三种种方式对比:

      调用方式是否刷新页面是否存在回调其他
      window.jsHelper具体看Native方法需Native创建js交互对象,并挂载在window上
      location.href需要Native进行拦截相应的url进行处理;连续多次调用只执行最后一次
      iframe.src需要Native进行拦截相应的url进行处理;
  • 🏷JsBridge

    • Native调用Web

      //functionInJs该方法需Web端注册
      webView.callHandler("functionInJs", "TEST BRIDGE", new JsCallBack() {
          @Override
          public void callBack(String result) {
              Log.e(TAG, "repsonseData from web, data = : "+result );
          }
      });
      //or
       webView.sendMessage("functionInJs", "TEST BRIDGE", new JsCallBack() {
                          @Override
                          public void callBack(String data) {
                               Log.e(TAG, "repsonseData from web, data = : "+result );
                          }
                      });
      
      
    • Web调用Native

      // functionInNative该方法需Native端注册
      window.WebViewJavascriptBridge.callHandler(
          'functionInNative'
          , params
          , function(responseData) {
              console.log("repsonseData from java, data = " + responseData);
          }
      );
      

1.2丶JsBridge交互方式和原生交互方式对比

交互方式调用链路交互方法优点缺点
原生交互NativeCallH5laodurl版本支持Android4.2以下,兼容较好 1.会刷新页面
2.无返回值
3.js属性值无法获取
evaluateJavascript支持Web返回值1.返回值是否存在由js方法决定
H5CallNativewindow对象结果同步返回 1.需Native声明js交互对象并挂载到Window上
location.href调用方便 1.无返回值且需要Native针对URL进行拦截处理
2.连续多次调用只执行最后一次
iframe.src独立窗口处理js交互 1.无返回值且需要Native针对URL进行拦截处理
JsBridge交互NativeCallH5sendMessage1.版本兼容良好
2.均存在返回值
3.调用方式简单
1.需要Native针对URL进行拦截处理
2.需Web注入jsbridge.js
3.交互方法需接收端进行注册
callHandler
H5CallNative

1.3丶JsBridge原理

js关键方法

Web端注册方法

// Web端注册方法
bridge.registerHandler("messageName", function(params, responseCallback) {
    if (responseCallback) {
   		// Web端给Native的结果回调
        responseCallback(responseData);
    }
});

JsBridge.js中的方法

registerHandler方法负责注册native调用Web的方法

// 注册native调用Web的方法
function registerHandler(messageName, handler) {
    messageHandlers[messageName] = handler;
}
// 保存web端当前页面的js交互的处理类,通过messageName进行保存和获取
var messageHandlers = {};

callHandler方法,用于Web调用Native的关键方法,其内部调用了_send方法

function callHandler(messageName, data, responseCallback) {
    _doSend({
        messageName: messageName,
        data: data
    }, responseCallback);
}

_doSend 方法用于Web端发送消息给Native侧,同时保存相应的回调对象,回调对象用于后面接收处理Native的回调结果

function _doSend(message, responseCallback) {
    console.log("调用链路: "+" _doSend message="+JSON.stringify(message));
    // 判断当前的responseCallback对象是否为空,该判断的作用是用于区分是Web端调用Native方法,还是Web主动通知Native去刷新消息队列
    if (responseCallback) {
        var callbackId = 'H5CallNative_cb_' + (uniqueId++) + '_' + new Date().getTime();
        // web保存调用Native方法时的回调对象,最后会在_dispatchMessageFromNative分发处理Native发送过来的消息时取出,并返回
        responseCallbacks[callbackId] = responseCallback;
        message.callbackId = callbackId;
    }
	// 保存Web端发送的消息信息
    sendMessageQueue.push(message);
    // iframe.src主动发送请求通知Native,该uri最终会执行到WebViewCilent中的shouldOverrideUrlLoading方法
    messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + QUEUE_HAS_MESSAGE;
}

_fetchQueue 方法,web侧提供给Native调用的方法,用于刷新消息队列信息,并把消息结果返回给Native

// 提供给native调用,该函数作用:获取sendMessageQueue中的数据返回给native,因为android不能直接获取返回的内容,因此使用url shouldOverrideUrlLoading 的方式返回内容
function _fetchQueue() {
    // 取出所有的发送消息的信息内容
    var messageQueueString = JSON.stringify(sendMessageQueue);
    console.log("调用链路: "+" _fetchQueue messageQueueString="+messageQueueString);
    // 置空消息队列
    sendMessageQueue = [];
    //android无法直接读取返回数据,因此我们可以重新加载iframe src以与java通信
    messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://return/_fetchQueue/' + encodeURIComponent(messageQueueString);
}

_handleMessageFromNative方法,用于Web侧处理native发送过来的消息

function _handleMessageFromNative(messageJSON) {
    console.log("调用链路: "+" _handleMessageFromNative messageJSON="+messageJSON);
    console.log("调用链路: "+" _handleMessageFromNative bool="+(receiveMessageQueue && receiveMessageQueue.length > 0));
    //页面加载完成时会清空消息队列,因此当重新初始化的时候,会把当前页面的js交互消息进行保存
    if (receiveMessageQueue && receiveMessageQueue.length > 0) {
        receiveMessageQueue.push(messageJSON);
    } else {
        // 分发处理Native发送过来的消息
        _dispatchMessageFromNative(messageJSON);
    }
}

_dispatchMessageFromNative 方法,分发处理Native发送过来的消息

function _dispatchMessageFromNative(messageJSON) {
    setTimeout(function() {
        var message = JSON.parse(messageJSON);
        var responseCallback;
        // Web调用native完成后,js获取结果的回调函数,
        if (message.responseId) {
            // 从responseCallbacks集合中取出结果回调,该回调是在web调用_doSend方法时进行保存的
            responseCallback = responseCallbacks[message.responseId];
            if (!responseCallback) {
                return;
            }
            responseCallback(message.responseData);
            // 从responseCallbacks集合中移除结果回调
            delete responseCallbacks[message.responseId];
        } else {
            // native主动调用Web方法,发送的消息
            if (message.callbackId) {
                var callbackResponseId = message.callbackId;
                responseCallback = function(responseData) {
                    // 当web处理native发送过来的消息结束后会调用该方法,发送消息给Native侧,通知已经处理好结果
                    _doSend({
                        responseId: callbackResponseId,
                        responseData: responseData
                    });
                };
            }

            var handler = WebViewJavascriptBridge._messageHandler;
            if (message.messageName) {
                // 取出处理Native调用web方法的处理函数对象,该对象是在Web端注册方法时进行保存的
                handler = messageHandlers[message.messageName];
            }
            //查找指定handler
            try {
                // 处理native发送过来的消息.该方法在Web端registerHandler注册方法中声明
                /**
                 *
                 * bridge.registerHandler("messageName", function(params, responseCallback) {
                 *     if (responseCallback) {
                 *    		// Web端给Native的结果回调
                 *         responseCallback(responseData);
                 *     }
                 * });
                 */
                
                handler(message.data, responseCallback);
            } catch (exception) {
                if (typeof console != 'undefined') {
                }
            }
        }
    });
}
native关键方法

registerHandler方法用于注册Web调用Native的方法

 /**
     * register handler,so that javascript can call it
     *
     * @param handlerName 方法名
     * @param handler 消息处理类
     */
    public void registerHandler(String handlerName, BridgeHandler handler) {
        if (handler != null) {
            messageHandlers.put(handlerName, handler);
        }
    }

callHandler方法,用于Native调用Web端方法

/**
 * native调用web方法
 *
 * @param messageName:方法名
 * @param data 方法参数
 * @param callBack 结果回调
 */
public void callHandler(String messageName, String data, JsCallBack callBack) {
    Log.e("调用链路: ",TAG+" callHandler  "+messageName+"=="+data);
    // 发送消息给web端
    doSend(messageName, data, callBack);
}

doSend方法:封装处理Native调用Web端的消息信息

/**
 * 发送消息给Web端
 * @param messageName 方法名
 * @param data 方法参数
 * @param responseCallback 结果回调
 */
private void doSend(String messageName, String data, JsCallBack responseCallback) {
    Log.e("调用链路: ",TAG+" doSend  "+messageName+"=="+data);
    // 创建js交互的信息对象
    JSMessage m = new JSMessage();
    // 设置消息参数
    if (!TextUtils.isEmpty(data)) {
        m.setParams(data);
    }
    // 设置消息回调对象
    if (responseCallback != null) {
        String callbackStr = String.format(JsBridgeUtil.CALLBACK_ID_FORMAT, ++uniqueId + (JsBridgeUtil.UNDERLINE_STR + SystemClock.currentThreadTimeMillis()));
        responseCallbacks.put(callbackStr, responseCallback);
        m.setCallbackId(callbackStr);
    }
    // 设置方法名
    if (!TextUtils.isEmpty(messageName)) {
        m.setMessageName(messageName);
    }
    Log.e("调用链路: ",TAG+" doSend messsge"+m.toJson());
    // 处理消息
    queueMessage(m);
}

queueMessage方法:用于保存或分发js交互的消息

/**
 * 发送消息给Web端
 * @param m js交互的信息
 */
private void queueMessage(JSMessage m) {
    // 页面加载完成时会清空消息队列,因此当重新初始化的时候,会把当前页面的js交互消息进行保存
    // 保pageMessage存页面的所有js交互信息;注意点:该集合只保存当前页面的交互数据,页面切换的时候需要手动置空,防止存在一个页面出现多次注册,多次接收的情况
    if (pageMessage != null) {
        pageMessage.add(m);
    } else {
        // 分发处理js交互的信息
        dispatchMessage(m);
    }
}

dispatchMessage方法

/**
 * 分发处理Native发送给Web端的消息
 * @param m js交互的信息
 */
void dispatchMessage(JSMessage m) {
    String messageJson = m.toJson();
    // json字符串的转义特殊字符
    messageJson = messageJson.replaceAll("(\\\\)([^utrn])", "\\\\\\\\$1$2");
    messageJson = messageJson.replaceAll("(?<=[^\\\\])(\")", "\\\\\"");
    // JS_HANDLE_MESSAGE_FROM_JAVA:javascript:WebViewJavascriptBridge._handleMessageFromNative('%s');调用js中的_handleMessageFromNative方法
    String javascriptCommand = String.format(JsBridgeUtil.JS_HANDLE_MESSAGE_FROM_JAVA, messageJson);
    Log.e("调用链路: ",TAG+" dispatchMessage "+javascriptCommand);
    if (Thread.currentThread() == Looper.getMainLooper().getThread()) {
        this.loadUrl(javascriptCommand);
    }
}

shouldOverrideUrlLoading 方法:用于处理拦截web端发送过来的消息

@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
    try {
        // url进行UTF-8编码
        url = URLDecoder.decode(url, "UTF-8");
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }
    Log.e("调用链路: ",TAG+" shouldOverrideUrlLoading url="+url);
    // RETURN_DATA_SCHAME:ebanma://return/ 代表了Native调用web端刷新消息队列是取出的消息信息,及刷新消息队列返回的消息结果
    if (url.startsWith(JsBridgeUtil.RETURN_DATA_SCHAME)) {
        // 处理Web侧返回的消息结果
        webView.handlerReturnData(url);
        return true;
        // OVERRIDE_SCHEMA:ebanma://__QUEUE_MESSAGE__/ 代表Web侧主动通知Native去刷新消息队列
    } else if (url.startsWith(JsBridgeUtil.OVERRIDE_SCHEMA)) {
        // 刷新消息队列
        webView.flushMessageQueue();
        return true;
    } else {
        // 此处为jsbridge的二次优化处理,判断当前url是否为web链接,还是Apk的schame跳转链接,
        if (urlCanLoad(url)) {
            return super.shouldOverrideUrlLoading(view, url);
        } else {
            // Web侧发送启动Apk的schame链接,通知Native去启动Apk
            startThirdpartyApp(url);
            return true;
        }
    }
}

handlerReturnData 方法:用于处理Web侧发送过来的消息结果

public void handlerReturnData(String url) {
    	//解析url获取回调方法名
        String functionName = JsBridgeUtil.getFunctionFromReturnUrl(url);
    	// 根据方法名从 responseCallbacks中取出回调对象,该回调对象在刷新消息队列的时进行保存
        JsCallBack f = responseCallbacks.get(functionName);
    	// 解析url获取回调结果
        String data = JsBridgeUtil.getDataFromReturnUrl(url);
        // 
        if (f != null) {
            // 回调flushMessageQueue中的callBack回调
            f.callBack(data);
            // 移除已处理的回调
            responseCallbacks.remove(functionName);
            return;
        }
    }

flushMessageQueue 方法

void flushMessageQueue() {
    Log.e("调用链路: ",TAG+" flushMessageQueue ");
    if (Thread.currentThread() == Looper.getMainLooper().getThread()) {
        Log.e("调用链路: ",TAG+" flushMessageQueue ="+JsBridgeUtil.JS_FETCH_QUEUE_FROM_JAVA);
        // javascript:WebViewJavascriptBridge._fetchQueue();执行js中的刷新消息队列的方法
        loadUrl(JsBridgeUtil.JS_FETCH_QUEUE_FROM_JAVA, new JsCallBack<String>() {
            // 刷新js中的消息队列并获取返回结果,具体执行该方法实在在handlerReturnData
            @Override
            public void callBack(String data) {
                Log.e("调用链路: ",TAG+" flushMessageQueue callBack="+data);
                // deserializeMessage
                List<JSMessage> list = null;
                try {
                    // 消息结果转换
                    list = JSMessage.toArrayList(data);
                } catch (Exception e) {
                    e.printStackTrace();
                    return;
                }
                if (list == null || list.size() == 0) {
                    return;
                }
                // 循环遍历消息
                for (int i = 0; i < list.size(); i++) {
                    JSMessage m = list.get(i);
                    String responseId = m.getResponseId();
                    // 根据消息结果中是否包含reponseId区分是Native调用Web给出的结果还是Web调用Native的消息
                    if (!TextUtils.isEmpty(responseId)) {//Native调用Web给出的结果
                        // 取出Native调用Web给出的结果回调,该回调实在调用loadUrl方法中进行的保存
                        JsCallBack function = responseCallbacks.get(responseId);
                        String responseData = m.getResponseData();
                        function.callBack(responseData);
                        responseCallbacks.remove(responseId);
                        Log.e("调用链路: ",TAG+" flushMessageQueue callBack="+responseData);
                    } else {//Web调用Native的消息
                        JsCallBack responseFunction = null;
                        // if had callbackId
                        final String callbackId = m.getCallbackId();
                        if (!TextUtils.isEmpty(callbackId)) {
                            responseFunction = new JsCallBack<String>() {
                                @Override
                                public void callBack(String data) {
                                   
                                }
                            };
                        } else {
                            responseFunction = new JsCallBack<String>() {
                                @Override
                                public void callBack(String data) {
                                    // do nothing
                                }
                            };
                        }
                        IBridgeHandler handler;
                        if (!TextUtils.isEmpty(m.getMessageName())) {
                            if (!TextUtils.isEmpty(m.getMessageName())) {
                                // 取出处理Web调用Native方法的处理函数,其在发送消息函数doSend中进行的保存
                                handler = messageHandlers.get(m.getMessageName());
                                if (handler == null) {
                                    handler = defaultHandler;
                                }
                                if (handler != null) {
                                    // 处理Web调用Native的方法
                                    handler.handler(m.getMessageName(), m.getParams(), responseFunction);
                                }
                            }
                        }else{
                            responseFunction.callBack("Web单纯的通知Native时,返回的数据");
                        }
                    }
                }
            }
        });
    }
}

loadUrl方法:执行js方法,并保存js交互方法的结果回调

public void loadUrl(String jsUrl, JsCallBack returnCallback) {
    this.loadUrl(jsUrl);
    // 保存Native调用Web时的回调对象
    responseCallbacks.put(JsBridgeUtil.parseFunctionName(jsUrl), returnCallback);
}

native中的responseCallbacks常量:保存Native调用Web时的回调对象,在doSend发送消息时保存,在处理结果返回时进行执行回调函数,并移除

native中的messageHandlers常量:保存Web调用Native的处理对象,其在Native注册函数时进行保存,在获取刷新消息队列信息的时候进行取出,并执行消息处理

js交互流程
  • Native调用Web流程说明

在这里插入图片描述

  • Web调用Native流程说明
    在这里插入图片描述

2丶JsBridge二次开发

2.1丶背景说明

  • 针对native侧处理Web调用Native的消息处理类需重复定义,并执行其相关方法;无统一处理,可在任意类中处理,维护较难,可读性差
  • 原jsBridge不能和原生的JavaScriptInterface交互方式兼容;
  • 原jsBridge交互时,Web与Native进行了四次通信,不仅浪费资源同样耗时,希望能够只交互两次,及发送消息,接收结果

2.2丶二次开发修改点:

  • 修改BridgeHandler的handler方法,新增messageName参数,用于消息分发时的判断处理

    /**
     * jsbrdige交互的能力分发
     *
     * @param name     方法名
     * @param data     方法参数
     * @param function 结果回调
     */
    void handler(String messageName, String data, JsCallBack function);
    
  • BridgeHandler的handler处理消息方法中进行消息统一执行处理

    /**
     * js交互的方法分发
     * 消息分发的处理类{@link AbstractBridgeMsgDispatch}
     * @param name     方法名
     * @param data     方法参数
     * @param function 结果回调
     */
    @Override
    public void handler(String name, String data, JsCallBack function) {
        Log.e("调用链路: ",TAG+" handler data="+data+" name= "+name);
        mBridgeHandler.handleMessage(name, data, function);
    }
    
  • AbstractBridgeMsgDispatch中统一进行消息分发,同时支持同步/异步执行

    /**
     * 统一分发
     *
     * @param messageName 消息名
     * @param params      参数
     * @param callback    方法回调
     * @return 执行结果
     */
    public String handleMessage(final String messageName, final String params, final JsCallBack callback) {
        if (callback == null) {
            return execNative(messageName, params);
        } else {
            TaskExecutor.executeTask(new Runnable() {
                @Override
                public void run() {
                    TaskExecutor.executeTask(() -> {
                        String response = execNative(messageName, params, callback);
                        TaskExecutor.runTaskOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                try {
                                    JSONObject jsonObject = new JSONObject(response);
                                    Object responseData = jsonObject.opt("data");
                                    // BaseAbilityHelper中每个case都需要给result赋值,
                                    // 除当前case为执行时回调为异步,result无需赋值,但是需要在当前的case中执行callback.onCallBack(response)
                                    if (responseData!=null){
                                        if (response.contains("data")){
                                            callback.callBack(response);
                                        }
                                    }
                                } catch (JSONException e) {
                                    e.printStackTrace();
                                }
                            }
                        });
                    });
                }
            });
            return null;
        }
    }
    
  • 消息的统一处理类BaseAbilityhelper

    /**
     * 基础能力通用处理类
     * 添加@JavascriptInterface,兼容JavascriptInterface交互方式
     * @param messageName 方法名
     * @param params      方法参数
     * @param callback    结果回调
     * @return 结果返回
     */
    @Keep
    @JavascriptInterface
    @Override
    public String execNative(String messageName, String params, JsCallBack callback) {
        String result = null;
        try {
            switch (messageName) {
                case MessageAction.h5_call_native_test:
                    result = "h5_call_native_test_result";
                    break;
                default:
                    return getUnSupportResponse(messageName);
            }
        } catch (Exception e) {
            return getErrorResponse(e.getMessage());
        }
        return getSuccessResponse(result);
    }
    
  • 修改jsBridge.js交互逻辑

    修改jsBridge.js文件

    //notation: js file can only use this kind of comments
    //since comments will cause error when use in webview.loadurl,
    //comments will be remove by java use regexp
    (function() {
        if (window.WebViewJavascriptBridge) {
            return;
        }
        var messagingIframe;
        var receiveMessageQueue = [];
        // 当前页面的js交互的处理类,通过messageName进行保存和获取
        var messageHandlers = {};
        // schame 协议的协议
        var CUSTOM_PROTOCOL_SCHEME = 'ebanma';
        var H5_CALL_NATIVE_MSG = 'h5CallNativeMsg/';
    
        var responseCallbacks = {};
        var uniqueId = 1;
    
        function _createQueueReadyIframe(doc) {
            messagingIframe = doc.createElement('iframe');
            messagingIframe.style.display = 'none';
            doc.documentElement.appendChild(messagingIframe);
        }
    
        //set default messageHandler
        function init(messageHandler) {
            if (WebViewJavascriptBridge._messageHandler) {
                throw new Error('WebViewJavascriptBridge.init called twice');
            }
            WebViewJavascriptBridge._messageHandler = messageHandler;
            var receivedMessages = receiveMessageQueue;
            receiveMessageQueue = null;
            for (var i = 0; i < receivedMessages.length; i++) {
                _handleNativeCallWebMessage(receivedMessages[i]);
            }
        }
    
        function send(data, responseCallback) {
            _callNative({
                data: data
            }, responseCallback);
        }
        // 注册native调用Web的方法
        function registerHandler(messageName, handler) {
        console.log("调用链路: "+" registerHandler messageName="+messageName);
        messageHandlers[messageName] = handler;
        }
    
        function callHandler(messageName, data, responseCallback) {
            _callNative({
                messageName: messageName,
                data: data
            }, responseCallback);
        }
        function _callNative(message,responseCallback){
           if (responseCallback) {
               var callbackId = 'H5CallNative_cb_' + (uniqueId++) + '_' + new Date().getTime();
               responseCallbacks[callbackId] = responseCallback;
               message.callbackId = callbackId;
           }
           messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + H5_CALL_NATIVE_MSG+JSON.stringify(message);
        }
    
        function _nativeCallH5Msg(messageJSON){
            console.log("调用链路: "+" _nativeCallH5Msg messageJSON="+JSON.stringify(messageJSON));
            console.log("调用链路: "+" _nativeCallH5Msg messageJSON="+(receiveMessageQueue && receiveMessageQueue.length > 0));
            if (receiveMessageQueue && receiveMessageQueue.length > 0) {
                receiveMessageQueue.push(messageJSON);
            } else {
                _handleNativeCallWebMessage(messageJSON);
            }
        }
        function _h5CallNativeResult(messageJSON){
           setTimeout(function() {
            console.log("调用链路: "+" _h5CallNativeResult message="+JSON.stringify(messageJSON));
               var message = JSON.parse(messageJSON);
               if (message.responseId) {
                   responseCallback = responseCallbacks[message.responseId];
                   if (!responseCallback) {
                       return;
                   }
                   console.log("调用链路: "+" _h5CallNativeResult message.responseData="+message.responseData);
                   responseCallback(message.responseData);
                   delete responseCallbacks[message.responseId];
               }
           });
        }
        function _handleNativeCallWebMessage(messageJSON){
            setTimeout(function() {
                console.log("调用链路: "+" _handleNativeCallWebMessage messageJSON="+JSON.stringify(messageJSON));
                var message = JSON.parse(messageJSON);
                if (message.callbackId) {
                    var callbackResponseId = message.callbackId;
                    var messageName = message.messageName;
                    responseCallback = function(responseData) {
                        console.log("调用链路: "+" _handleNativeCallWebMessage responseCallback="+responseData);
                        _nativeCallH5MsgResult({
                           messageName: messageName,
                           responseId: callbackResponseId,
                           responseData: responseData
                        });
                    };
                }
                var handler = WebViewJavascriptBridge._messageHandler;
                if (message.messageName) {
                    handler = messageHandlers[message.messageName];
                }
                //查找指定handler
                try {
                    handler(message.data, responseCallback);
                } catch (exception) {
                    if (typeof console != 'undefined') {}
                }
            });
        }
        function _nativeCallH5MsgResult(message){
           messageQueueString = JSON.stringify(message);
           console.log("调用链路: "+" _nativeCallH5MsgResult messageQueueString="+messageQueueString);
           //android can't read directly the return data, so we can reload iframe src to communicate with java
           messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://nativeCallH5MsgResult/' + encodeURIComponent(messageQueueString);
    
        }
    
        var WebViewJavascriptBridge = window.WebViewJavascriptBridge = {
            init: init,
            send: send,
            registerHandler: registerHandler,
            callHandler: callHandler,
            _nativeCallH5Msg: _nativeCallH5Msg,
            _h5CallNativeResult: _h5CallNativeResult,
        };
    
        var doc = document;
        _createQueueReadyIframe(doc);
        var readyEvent = doc.createEvent('Events');
        readyEvent.initEvent('WebViewJavascriptBridgeReady');
        readyEvent.bridge = WebViewJavascriptBridge;
        doc.dispatchEvent(readyEvent);
    })();
    

    修改WebViewClient中url拦截方法的处理逻辑,仅保留Web调用Native方法以及Web回调Native结果的

    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        try {
            url = URLDecoder.decode(url, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        Log.e("调用链路: ",TAG+" shouldOverrideUrlLoading url="+url);
        if (url.startsWith(JsBridgeUtil.NATIVE_CALL_H5_RESULT)) {
            webView.handlerNativeCallH5Result(url);
            return true;
        }else if (url.startsWith(JsBridgeUtil.H5_CALL_NATIVE_MSG)) {
            webView.handlerH5CallNativeMsg(url);
            return true;
        }else {
            if (urlCanLoad(url)) {
                return super.shouldOverrideUrlLoading(view, url);
            } else {
                startThirdpartyApp(url);
                return true;
            }
        }
    }
    

    修改Native调用web方法:直接发送请求信息通知到Web侧

    void reallCallWeb(JSMessage m) {
        String messageJson = m.toJson();
        //escape special characters for json string
        messageJson = messageJson.replaceAll("(\\\\)([^utrn])", "\\\\\\\\$1$2");
        messageJson = messageJson.replaceAll("(?<=[^\\\\])(\")", "\\\\\"");
        String javascriptCommand = String.format(JsBridgeUtil.NATIVE_CALL_H5_HANDLE_MESSSAGE, messageJson);
        Log.e("调用链路: ", TAG + " reallCallWeb " + javascriptCommand);
        if (Thread.currentThread() == Looper.getMainLooper().getThread()) {
            this.loadUrl(javascriptCommand);
        }
    }
    

    修改Native接收Web请求的方法:执行结果后,直接返回Web回调结果

    public void handlerH5CallNativeMsg(String url) {
        if (url.startsWith(JsBridgeUtil.H5_CALL_NATIVE_MSG)) {
            String temp = url.replace(JsBridgeUtil.H5_CALL_NATIVE_MSG, EMPTY_STR);
            JSMessage m= new Gson().fromJson(temp,JSMessage.class);
            JsCallBack responseFunction = null;
            // if had callbackId
            final String callbackId = m.getCallbackId();
            if (!TextUtils.isEmpty(callbackId)) {
                responseFunction = new JsCallBack<String>() {
                    @Override
                    public void callBack(String data) {
    
                        JSMessage responseMsg = new JSMessage();
                        responseMsg.setResponseId(callbackId);
                        responseMsg.setResponseData(data);
                        String messageJson = responseMsg.toJson();
                        Log.e("调用链路: ", TAG + " handlerH5CallNativeMsg callBack=" + messageJson);
                        //escape special characters for json string
                        messageJson = messageJson.replaceAll("(\\\\)([^utrn])", "\\\\\\\\$1$2");
                        messageJson = messageJson.replaceAll("(?<=[^\\\\])(\")", "\\\\\"");
                        String javascriptCommand = String.format(JsBridgeUtil.H5_CALL_NATIVE_RESULT, messageJson);
                        Log.e("调用链路: ", TAG + "handlerH5CallNativeMsg callBack " + javascriptCommand);
                        if (Thread.currentThread() == Looper.getMainLooper().getThread()) {
                            loadUrl(javascriptCommand);
                        }
                    }
                };
            } else {
                responseFunction = new JsCallBack<String>() {
                    @Override
                    public void callBack(String data) {
                        // do nothing
                    }
                };
            }
            IBridgeHandler handler;
            if (!TextUtils.isEmpty(m.getMessageName())) {
                if (!TextUtils.isEmpty(m.getMessageName())) {
                    handler = messageHandlers.get(m.getMessageName());
                    if (handler == null) {
                        handler = defaultHandler;
                    }
                    if (handler != null) {
                        handler.handler(m.getMessageName(), m.getParams(), responseFunction);
                    }
                }
            } else {
                responseFunction.callBack("Web单纯的通知Native时,返回的数据");
            }
        }
    }
    
新js交互流程图
  • Native调用Web流程说明
    在这里插入图片描述

  • Web调用Native流程说明

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值