jsbridge实现及原理_如何实现一个优雅的jsBridge
什么是jsbridge
jsbridge是客戶端和H5溝通的橋梁,通過它,我們可以獲取部分原生能力,同時客戶端也可以使用我們提供的一些方法。實現雙向通信。
jsbridge原理
客戶端可以通過webview里面注入一些javascript的上下文,可以理解為在window對象上掛載了一些方法,然后H5通過特定的對象可以獲取到這個方法,反過來也是一樣,js掛載了一些方法到window對象上,客戶端也就可以調用js的某些方法。
具體實現
方案一:注入API
IOS UIWebView
JSContext *context = [uiWebView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
context[@"postBridgeMessage"] = ^(NSArray *calls) {
// Native 邏輯
};
H5使用window.postBridgeMessage(message)調用
IOS WKWebView
@interface WKWebVIewVC ()
@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)方式調用。
來看一下H5端具體實現
假設我們需要一個getUserInfo方法,用于H5獲取當前APP登錄用戶的信息。
那么我們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);
}
});
}
我們定義一個getUserInfo方法,這個方法會去調用window.webkit.messageHandlers.getUserInfo.postMessage方法,這是客戶端寫入的方法,然后傳入一個callback方法??蛻舳藭ㄟ^callback方法把我們需要的信息返回給我們。
我們可以再看下registerCallback這個方法是什么:
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。
Android
客戶端實現:
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);
}
});
}
方案二:url攔截
這種方案就是H5構造一個iframe,通過給iframe設置src發起請求,然后客戶端攔截請求實現。
一般會將url設為一個特殊的字符串,比如https://__bridge__這個樣子,然后后面跟上我們需要傳遞的數據,包括一個callback函數名,客戶攔截這種請求,然后通過callback將數據傳遞回來。
前端收藏家(微信號: fedaily)
收集全網優秀前端技術資訊,與你分享,共同成長。
總結
以上是生活随笔為你收集整理的jsbridge实现及原理_如何实现一个优雅的jsBridge的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: babel css3新特性_2018年面
- 下一篇: if break语句_8、嵌套if语句、