js-native 通信的 6 种方式

本文介绍了6种JS与Native通信的方式,包括postMessage、prompt、iframe、注入JS、location.href以及addJavaScriptInterface,详细讲解了每种方式的实现原理和应用场景,适用于多端统一的App开发中确保API的一致性。

端能力是 App 开发中非常重要的基础技术,在 js-native 这种框架研发过程中要保证多端统一,也就是说在 H5 页面中当调用一个端能力的时候,需要提供统一的调用 API,如下:

// bad
function getSystemInfo() {
    if (isIos) {
        // send msg to iOS
    }
    else if (isAndroid) {
        // send msg to android
    }
}
// good
function getSystemInfo() {
    // send msg to all platform
}

要想保证 API 的一致性,必须对 JS 与 Native 通信的方式有一个彻底的了解。我主要了解到以下几种通信方式:

postMessage(iOS WKWebview)

这种方式是在 iOS 中处理消息非常方便,但是在 Android 中并不支持。

- (void)userContentController:(WKUserContentController *)uc
didReceiveScriptMessage:(WKScriptMessage *)message
{
    // 接收到消息,并处理
}
// 消息发送
window.webkit.messageHandlers.SYJSBridge.postMessage(msg);

prompt(iOS/Android Webview)

巧用 webview 的弹窗,弹窗内容定义消息体,显然这种方式对于处理消息很不方便,纯粹的做字符串解析。

前端实现(消息发送):

window.prompt(msg);

iOS 端实现(接收消息):

- (void)webView:(WKWebView *)webView 
runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt 
defaultText:(NSString *)defaultText 
initiatedByFrame:(WKFrameInfo *)frame 
completionHandler:(void (^)(NSString *))completionHandler
{
    completionHandler(@"OC input");
}

iframe(iOS/Android Webview)

创建一个隐形的 iframe,Native 侧会收到一个请求,可以通过请求地址来做一个处理,达到通信的目的。

前端调用实现(发送消息)

// js 侧进行消息发送
const callIframe = function(url) {
    var iframe = document.createElement('iframe');
    iframe.src = url;
    document.body.appendChild(iframe);
    document.body.removeChild(iframe);
}

iOS 端实现(接收消息):

// native 接收到消息
- (void)webView:(WKWebView *)webView
decidePolicyForNavigationAction:(WKNavigationAction *)na 
decisionHandler:(void (^)(WKNavigationActionPolicy))h {
    NSLog(@"%@", NSStringFromSelector(_cmd));
    decisionHandler(WKNavigationActionPolicyAllow);
}

注入 JS(iOS WKWebView)

这种方式主要通过 webview 提供的 API 向 JavaScript 执行引擎中注入 JavaScript 代码。下面的代码在页面加载时注入了一个 add 函数,这个函数被挂载到了 window 下,在网页中可直接调用。

iOS 端实现:

WKUserScript *script = [[WKUserScript alloc] 
initWithSource:@"function add(a, b) { return a + b; }"
injectionTime:WKUserScriptInjectionTimeAtDocumentStart 
forMainFrameOnly:YES];
[webview.configuration.userContentController addUserScript:script];

location.href(iOS/Android Webview)

这种方式和第 3 种方法类似,不过需要对做通信 API 的路由做拦截处理,否则会跳转到新的页面。下面我简单处理了这个过程:

前端调用实现(发送消息):

window.location.href = url;

iOS 端实现(接收消息):

- (void)webView:(WKWebView *)webView 
decidePolicyForNavigationAction:(WKNavigationAction *)na 
decisionHandler:(void (^)(WKNavigationActionPolicy))d {
    NSLog(@"%@", NSStringFromSelector(_cmd));
    if ([na.request.URL.absoluteString containsString:@"suyan"]) {
        d(WKNavigationActionPolicyCancel);
    }
    else {
        d(WKNavigationActionPolicyAllow);
    }
}

addJavaScriptInterface(Android Webview)

把一个 Java 对象注入到 JavaScript 执行环境当中,使得在 webivew 中可直接调用该方法,间接调用 Native 方法。

参考:

https://github.com/ecomfe/js-native

长按关注

素燕《前端小课》

帮助 10W 人入门并进阶前端

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值