JSBridge的原理及使用


一、什么是JSBridge

主要是給 JavaScript 提供調用 Native 功能的接口,讓混合開發中的前端部分可以方便地使用 Native 的功能(例如:地址位置、攝像頭)。
而且 JSBridge 的功能不止調用 Native 功能這么簡單寬泛。實際上,JSBridge 就像其名稱中的Bridge的意義一樣,是 Native 和非 Native 之間的橋梁,它的核心是構建 Native 和非 Native消息通信的通道,而且這個通信的通道是雙向的。

雙向通信的通道:

JS 向 Native 發送消息: 調用相關功能、通知 Native 當前 JS 的相關狀態等。
Native 向 JS 發送消息: 回溯調用結果、消息推送、通知 JS 當前 Native 的狀態等。

H5與Native交互如下圖:

二、JSBridge 的實現原理

JavaScript 是運行在一個單獨的 JS Context 中(例如,WebView 的 Webkit 引擎、JSCore)。由於這些 Context 與原生運行環境的天然隔離,我們可以將這種情況與 RPCRemote Procedure Call,遠程過程調用)通信進行類比,將 Native 與 JavaScript 的每次互相調用看做一次 RPC 調用。

在 JSBridge 的設計中,可以把前端看做 RPC 的客戶端,把 Native 端看做 RPC 的服務器端,從而 JSBridge 要實現的主要邏輯就出現了:通信調用(Native 與 JS 通信) 和句柄解析調用

三、JSBridge 的通信原理

3.1.JavaScript 調用 Native的方式

主要有兩種:注入API 和 攔截URL SCHEME。

3.1.1 注入API

主要原理:

  • 通過 WebView 提供的接口,向 JavaScript 的 Context(window)中注入對象或者方法,讓 JavaScript 調用時,直接執行相應的 Native 代碼邏輯,達到 JavaScript 調用 Native 的目的。

對於 iOS 的 UIWebView,實例如下:

JSContext *context = [uiWebView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];

context[@"postBridgeMessage"] = ^(NSArray<NSArray *> *calls) {
    // Native 邏輯
};


//前端調用方式:
window.postBridgeMessage(message);

對於 iOS 的 WKWebView 可以用以下方式:

@interface WKWebVIewVC ()<WKScriptMessageHandler>

@implementation WKWebVIewVC

- (void)viewDidLoad {
    [super viewDidLoad];

    WKWebViewConfiguration* configuration = [[WKWebViewConfiguration alloc] init];
    configuration.userContentController = [[WKUserContentController alloc] init];
    WKUserContentController *userCC = configuration.userContentController;
    // 注入對象,前端調用其方法時,Native 可以捕獲到
    [userCC addScriptMessageHandler:self name:@"nativeBridge"];

    WKWebView wkWebView = [[WKWebView alloc] initWithFrame:self.view.frame configuration:configuration];

    // TODO 顯示 WebView
}

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
    if ([message.name isEqualToString:@"nativeBridge"]) {
        NSLog(@"前端傳遞的數據 %@: ",message.body);
        // Native 邏輯
    }
}

// 前端調用方式:
window.webkit.messageHandlers.nativeBridge.postMessage(message);

3.1.2 攔截 URL SCHEME

URL SCHEME

  • 是一種類似於url的鏈接,是為了方便app直接互相調用設計的,形式和普通的 url 近似,主要區別是 protocol 和 host 一般是自定義的

例如:

qunarhy://hy/url?url=ymfe.tech,
protocol 是 qunarhy,host 則是 hy。

攔截 URL SCHEME 的主要流程是

  • Web 端通過某種方式(例如 iframe.src)發送 URL Scheme 請求,之后 Native 攔截到請求並根據 URL SCHEME(包括所帶的參數)進行相關操作。

在時間過程中,這種方式有一定的缺陷

  • 使用 iframe.src 發送 URL SCHEME 會有 url 長度的隱患。

    • 有些方案為了規避 url 長度隱患的缺陷,在 iOS 上采用了使用 Ajax 發送同域請求的方式,並將參數放到 head 或 body 里。這樣,雖然規避了 url 長度的隱患,但是 WKWebView 並不支持這樣的方式
    • 為什么選擇 iframe.src 不選擇 locaiton.href ?
      • 因為如果通過 location.href 連續調用 Native,很容易丟失一些調用。
  • 創建請求,需要一定的耗時,比注入 API 的方式調用同樣的功能,耗時會較長。

因此:JavaScript 調用 Native 推薦使用注入 API 的方式

3.2.Native 調用 JavaScript 的方式

相比於 JavaScript 調用 Native, Native 調用 JavaScript 較為簡單,直接執行拼接好的 JavaScript 代碼即可。

從外部調用 JavaScript 中的方法,因此 JavaScript 的方法必須在全局的 window 上。

對於 iOS 的 UIWebView,示例如下:

result = [uiWebview stringByEvaluatingJavaScriptFromString:javaScriptString];

* javaScriptString為JavaScript 代碼串

對於 iOS 的 WKWebView,示例如下:

[wkWebView evaluateJavaScript:javaScriptString completionHandler:completionHandler];

四、JSBridge 接口實現

從上面的剖析中,可以得知,JSBridge 的接口主要功能有兩個:調用 Native(給 Native 發消息) 和 接被 Native 調用(接收 Native 消息)。因此,JSBridge 可以設計如下:

window.JSBridge = {
    // 調用 Native
    invoke: function(msg) {
        // 判斷環境,獲取不同的 nativeBridge
        nativeBridge.postMessage(msg);
    },
    receiveMessage: function(msg) {
        // 處理 msg
    }
};

在上面部分中,提到過 RPC 中有一個非常重要的環節是 句柄解析調用 ,這點在 JSBridge 中體現為 句柄與功能對應關系。同時,我們將句柄抽象為 橋名(BridgeName),最終演化為一個 BridgeName 對應一個 Native 功能或者一類 Native 消息。基於此點,JSBridge 的實現可以優化為如下:

window.JSBridge = {
    // 調用 Native
    invoke: function(bridgeName, data) {
        // 判斷環境,獲取不同的 nativeBridge
        nativeBridge.postMessage({
            bridgeName: bridgeName,
            data: data || {}
        });
    },
    receiveMessage: function(msg) {
        var bridgeName = msg.bridgeName,
            data = msg.data || {};
        // 具體邏輯
    }
};

終極提問:消息都是單向的,那么調用 Native 功能時 Callback 怎么實現的?

對於 JSBridge 的 Callback ,其實就是 RPC 框架的回調機制。當然也可以用更簡單的 JSONP 機制解釋:

當發送 JSONP 請求時,url 參數里會有 callback 參數,其值是 當前頁面唯一 的,而同時以此參數值為 key 將回調函數存到 window 上,隨后,服務器返回 script 中,也會以此參數值作為句柄,調用相應的回調函數。

整體流程:

在 Native 端配合實現 JSBridge 的
JavaScript 調用 Native 主要的代碼邏輯是:接收到 JavaScript 消息 => 解析參數,拿到 bridgeName、data 和 callbackId => 根據 bridgeName 找到功能方法,以 data 為參數執行 => 執行返回值和 callbackId 一起回傳前端

Native調用 JavaScript 也同樣簡單,直接自動生成一個唯一的 ResponseId,並存儲句柄,然后和 data 一起發送給前端即可。

五、JSBridge 的引用

對於 JSBridge 的引用,常用有如下兩種方式,但各有利弊。

5.1.由 Native 端進行注入

注入方式和 Native 調用 JavaScript 類似,直接執行橋的全部代碼

  • 優點是
    • 橋的版本很容易與 Native 保持一致,Native 端不用對不同版本的 JSBridge 進行兼容。
  • 缺點是:
    • 注入時機不確定,需要實現注入失敗后重試的機制,保證注入的成功率,同時 JavaScript 端在調用接口時,需要優先判斷 JSBridge 是否已經注入成功。

5.2.由 JavaScript 端引用

直接與 JavaScript 一起執行。

  • 優點是:
    • JavaScript 端可以確定 JSBridge 的存在,直接調用即可。
  • 缺點是:
    • 如果橋的實現方式有更改,JSBridge 需要兼容多版本的 Native Bridge 或者 Native Bridge 兼容多版本的 JSBridge。

原文鏈接:https://blog.csdn.net/yuzhengfei7/java/article/details/93468914


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM