2024年Web前端最新JSBridge原理解析—以WebviewJavascriptBridge实现方式为例,2024年最新京东java面试题技术面

最后

文章到这里就结束了,如果觉得对你有帮助可以点个赞哦

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

JSBridge 是一种 webview 侧和 native 侧进行通信的手段,webview 可以通过 jsb 调用 native 的能力,native 也可以通过 jsb 在 webview 上执行一些逻辑。

二、JSB 的实现方式


在比较流行的 JSBridge 中,主要是通过拦截 URL 请求来达到 native 端和 webview 端相互通信的效果的。

这里我们以比较火的 WebviewJavascriptBridge 为例,来解析一下它的实现方式。

源码地址:https://github.com/marcuswestin/WebViewJavascriptBridge

2-1、在 native 端和 webview 端注册 Bridge

注册的时候,需要在 webview 侧和 native 侧分别注册 bridge,其实就是用一个对象把所有函数储存起来。

function registerHandler(handlerName, handler) {

messageHandlers[handlerName] = handler;

}

- (void)registerHandler:(NSString *)handlerName handler:(WVJBHandler)handler {

_base.messageHandlers[handlerName] = [handler copy];

}

2-2、在 webview 里面注入初始化代码

function setupWebViewJavascriptBridge(callback) {

if (window.WebViewJavascriptBridge) { return callback(WebViewJavascriptBridge); }

if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback); }

window.WVJBCallbacks = [callback];

var WVJBIframe = document.createElement(‘iframe’);

WVJBIframe.style.display = ‘none’;

WVJBIframe.src = ‘https://bridge_loaded’;

document.documentElement.appendChild(WVJBIframe);

setTimeout(function() { document.documentElement.removeChild(WVJBIframe) }, 0)

}

这段代码主要做了以下几件事:

(1)创建一个名为 WVJBCallbacks 的数组,将传入的 callback 参数放到数组内

(2)创建一个 iframe,设置不可见,设置 src 为https://__bridge_loaded__

(3)设置定时器移除这个 iframe

2-3、在 native 端监听 URL 请求

iOS 中有两种 webview,一种是 UIWebview,另一种是 WKWebview,这里以 WKWebview 为例:

- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler {

if (webView != _webView) { return; }

__strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate;

if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:decidePolicyForNavigationResponse:decisionHandler:)]) {

[strongDelegate webView:webView decidePolicyForNavigationResponse:navigationResponse decisionHandler:decisionHandler];

}

else {

decisionHandler(WKNavigationResponsePolicyAllow);

}

}

这段代码主要做了以下几件事:

(1)拦截了所有的 URL 请求并拿到 url

(2)首先判断isWebViewJavascriptBridgeURL,判断这个 url 是不是 webview 的 iframe 触发的,具体可以通过 host 去判断。

(3)继续判断,如果是isBridgeLoadedURL,那么会执行injectJavascriptFile方法,会向 webview 中再次注入一些逻辑,其中最重要的逻辑就是,在 window 对象上挂载一些全局变量和WebViewJavascriptBridge属性,具体值如下:

window.WebViewJavascriptBridge = {

registerHandler: registerHandler,

callHandler: callHandler,

disableJavscriptAlertBoxSafetyTimeout: disableJavscriptAlertBoxSafetyTimeout,

_fetchQueue: _fetchQueue,

_handleMessageFromObjC: _handleMessageFromObjC

};

var sendMessageQueue = [];

var messageHandlers = {};

var responseCallbacks = {};

var uniqueId = 1;

(4)继续判断,如果是 isQueueMessageURL,那么这就是个处理消息的回调,需要执行一些消息处理的方法(第四步会详细讲)

2-4、webview 调用 native 能力

当 native 和 webview 都注册好了 Bridge 之后,双方就可以互相调用了,这里先介绍 webview 调用 native 能力的过程。

2-4-1、webview 侧 callHandler

当 webview 调用 native 时,会调用 callHandler 方法,这个方法具体逻辑如下:

bridge.callHandler(‘ObjC Echo’, {‘key’:‘value’}, function responseCallback(responseData) {

console.log(“JS received response:”, responseData)

})

function callHandler(handlerName, data, responseCallback) {

if (arguments.length == 2 && typeof data == ‘function’) {

responseCallback = data;

data = null;

}

_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;

}

sendMessageQueue.push(message);

messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + ‘😕/’ + QUEUE_HAS_MESSAGE;

}

实际上就是先生成一个 message,然后 push 到 sendMessageQueue 里,然后更改 iframe 的 src。

2-4-2、native 侧 flushMessageQueue

然后,当 native 端检测到 iframe src 的变化时,会走到 isQueueMessageURL 的判断逻辑,然后执行 WKFlushMessageQueue 函数,获取到 JS 侧的 sendMessageQueue 中的所有 message。

- (void)WKFlushMessageQueue {

[_webView evaluateJavaScript:[_base webViewJavascriptFetchQueyCommand] completionHandler:^(NSString* result, NSError* error) {

if (error != nil) {

NSLog(@“WebViewJavascriptBridge: WARNING: Error when trying to fetch data from WKWebView: %@”, error);

}

[_base flushMessageQueue:result];

}];

}

- (void)flushMessageQueue:(NSString *)messageQueueString{

if (messageQueueString == nil || messageQueueString.length == 0) {

NSLog(@“WebViewJavascriptBridge: WARNING: ObjC got nil while fetching the message queue JSON from webview. This can happen if the WebViewJavascriptBridge JS is not currently present in the webview, e.g if the webview just loaded a new page.”);

return;

}

id messages = [self _deserializeMessageJSON:messageQueueString];

for (WVJBMessage* message in messages) {

if (![message isKindOfClass:[WVJBMessage class]]) {

NSLog(@“WebViewJavascriptBridge: WARNING: Invalid %@ received: %@”, [message class], message);

continue;

}

[self _log:@“RCVD” json:message];

NSString* responseId = message[@“responseId”];

if (responseId) {

WVJBResponseCallback responseCallback = _responseCallbacks[responseId];

responseCallback(message[@“responseData”]);

[self.responseCallbacks removeObjectForKey:responseId];

} else {

WVJBResponseCallback responseCallback = NULL;

NSString* callbackId = message[@“callbackId”];

if (callbackId) {

responseCallback = ^(id responseData) {

if (responseData == nil) {

最后

文章到这里就结束了,如果觉得对你有帮助可以点个赞哦

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

ack responseCallback = NULL;

NSString* callbackId = message[@“callbackId”];

if (callbackId) {

responseCallback = ^(id responseData) {

if (responseData == nil) {

最后

文章到这里就结束了,如果觉得对你有帮助可以点个赞哦

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

[外链图片转存中…(img-t8zUs2bb-1715425219908)]

  • 11
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值