jsbridge是客戶端和H5溝通的橋樑,經過它,咱們能夠獲取部分原生能力,同時客戶端也能夠使用咱們提供的一些方法。實現雙向通訊。javascript
客戶端能夠經過webview裏面注入一些javascript的上下文,能夠理解爲在window對象上掛載了一些方法,而後H5經過特定的對象能夠獲取到這個方法,反過來也是同樣,js掛載了一些方法到window對象上,客戶端也就能夠調用js的某些方法。前端
JSContext *context = [uiWebView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]; context[@"postBridgeMessage"] = ^(NSArray<NSArray *> *calls) { // Native 邏輯 };
H5使用window.postBridgeMessage(message)
調用java
@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 邏輯 } }
H5使用window.webkit.messageHandlers.nativeBridge.postMessage(message)
方式調用。android
來看一下H5端具體實現ios
假設咱們須要一個getUserInfo
方法,用於H5獲取當前APP登陸用戶的信息。web
那麼咱們js能夠這樣:promise
import registerCallback from '../registerCallback'; export default function getUserInfo() { return new Promise((resolve, reject) => { try { window.webkit.messageHandlers.getUserInfo.postMessage({ callback: registerCallback(resolve), }); } catch (e) { reject(e); } }); }
咱們定義一個getUserInfo
方法,這個方法會去調用window.webkit.messageHandlers.getUserInfo.postMessage
方法,這是客戶端寫入的方法,而後傳入一個callback方法。客戶端會經過callback方法把咱們須要的信息返回給咱們。微信
咱們能夠再看下registerCallback
這個方法是什麼:dom
window.knCallbacks = {}; function makeRandomId(func) { return `${func.name || 'anonymous'}_${Date.now()}`; } export default function registerCallback(callback, keepAlive) { if (!callback) { return null; } const callbackId = makeRandomId(callback); window.knCallbacks[callbackId] = (data) => { let result; if (typeof data === 'object') { result = data; } else if (typeof data === 'string') { try { result = JSON.parse(data); } catch (e) { result = data; } } callback(result); if (!keepAlive) { delete window.knCallbacks[callbackId]; } }; return `knCallbacks.${callbackId}`; }
在這個方法裏面,咱們會爲promise的resolve方法生成一個隨機函數名,避免出現window可能會有同名函數致使將其覆蓋的問題。
而後咱們根據生成的函數名重寫一個函數,將這個函數最後返回給外部的callback,傳遞給了客戶端。
這裏的data就是客戶端調用callback傳遞過來的數據。
咱們在這裏對數據作一些處理,而後給到callback,也就是promise的resolve。ide
客戶端實現:
publicclassJavaScriptInterfaceDemoActivityextendsActivity{ private WebView Wv; @Override publicvoidonCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); Wv = (WebView)findViewById(R.id.webView); final JavaScriptInterface myJavaScriptInterface = new JavaScriptInterface(this); Wv.getSettings().setJavaScriptEnabled(true); Wv.addJavascriptInterface(myJavaScriptInterface, "knJSBridge"); // TODO 顯示 WebView } publicclassJavaScriptInterface{ Context mContext; JavaScriptInterface(Context c) { mContext = c; } publicvoidpostMessage(String webMessage){ // Native 邏輯 } } }
H5實現
import registerCallback from '../registerCallback'; export default function getUserInfo() { return new Promise((resolve, reject) => { try { window.knJSBridge.getUserInfo(JSON.stringify({ callback: registerCallback(resolve), })); } catch (e) { reject(e); } }); }
這裏咱們其實能夠看到,knJSBridge實際上是咱們和客戶端約定的一個字段。而後咱們經過window.knJSBridge
就能夠調用客戶端的方法了。
registerCallback和IOS的是同樣的。
根據上面咱們H5這裏最後能夠實現這樣一個結構的jsbridge
jsbridge - index.js - ios/ - index.js - getUserInfo.js - android/ - index.js - getUserInfo.js
// jsbridge/index.js import iosBridge from './iOs'; import androidBridge from './android'; export default class Bridge { constructor() { super(); if (isAndroid) { this.jsbridge = androidBridge; } else { this.jsbridge = iosBridge; } } getUserInfo = (...args) => this.jsbridge.getUserInfo(...args); } // ios/index.js import getUserInfo from './getUserInfo'; export { getUserInfo } // ios/getUserInfo.js import registerCallback from '../registerCallback'; export default function getUserInfo() { return new Promise((resolve, reject) => { try { window.webkit.messageHandlers.getUserInfo.postMessage({ callback: registerCallback(resolve), }); } catch (e) { reject(e); } }); } // android/index.js import getUserInfo from './getUserInfo'; export { getUserInfo } // android/getUserInfo.js import registerCallback from '../registerCallback'; export default function getUserInfo() { return new Promise((resolve, reject) => { try { window.webkit.messageHandlers.getUserInfo.postMessage({ callback: registerCallback(resolve), }); } catch (e) { reject(e); } }); }
這種方案就是H5構造一個iframe,經過給iframe設置src發起請求,而後客戶端攔截請求實現。
通常會將url設爲一個特殊的字符串,好比https://__bridge__
這個樣子,而後後面跟上咱們須要傳遞的數據,包括一個callback函數名,客戶攔截這種請求,而後經過callback將數據傳遞回來。