YongSir

专业程序员伪装者

JS 和 OC 交互探索

在iOS中往往需要跟JS交互的需求,比如某些营销活动之类的,比如抢红包等等

前端的优势在于快速,便捷,样式灵活,这直接关乎产品的市场表现,怎样将其与本地app结合,一直是很多大厂尝试的事,甚至会给所有的开发都带来一场革命,对,我说的就是F8上的ReactNative

不过,现实情况是框架还不完善,体验稳定性都问题,眼下还没有大量的推广,何况apple真的会开放iOS这么大块饼吗?我看未必

我们能做的就是尽量在当下,完成简单的跟web的互调而已,而现实是这点儿也将将够用

本篇不聊原理不谈愿景,只介绍一款优秀的第三方框架和笔者自己使用过程中的一点儿心得

  • WebViewJavascriptBridge

这是一款老牌的框架,从11年就有了到现在已经快5年了,一直更新到现在,在github有5K+的star

借助代码看看其使用:

在使用时仅仅自然需要webView,在iOS8之前都是普通的webView,iOS8之后还有一个WKWebView

这里给VC绑定一个webView,like this:

添加属性:

1
2
@property (nonatomic, strong) UIWebView *webView;
@property (nonatomic, strong) WebViewJavascriptBridge *bridge;

然后在viewDidLoad方法中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

// 获取本地html
NSString *htmlPath = [[NSBundle mainBundle] pathForResource:@"ZXDemo.html" ofType:nil];
self.webView = [[UIWebView alloc] initWithFrame:self.view.bounds];

NSString *str = [NSString stringWithContentsOfFile: htmlPath encoding:NSUTF8StringEncoding error:nil];

// webView 加载 html
[self.webView loadHTMLString:str baseURL: [NSURL fileURLWithPath:htmlPath]];

// 添加webView
[self.view addSubview:self.webView];

// 创建一个Btn
[self createBtn];

同时还创建了一个本地的btn

这个框架认定JS和OC之间有两种层次的交互需求:发消息传东西2种,一种仅仅只是为了通信,另一种更重量的使用是相互调方法

想想也是,很多时候并不需要一定要告诉我要怎样操作,仅仅是传递个我一个值就可以了,而有的时候最好能直接调用某一边的方法,其实稍后你就会发现其实两种都是一样的

通信

可以理解为仅仅就是为了传值,使用灵活简便

  • JS 给 OC 传值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // OC中初始化
    self.bridge = [WebViewJavascriptBridge bridgeForWebView:self.webView webViewDelegate:self handler:^(id data, WVJBResponseCallback responseCallback) {

    NSLog(@" data: %@", data);
    responseCallback(@"back");

    }];

    ---------------------

    // JS中
    bridge.send(data, function(responseData) {
    log('[[JS中]] got response', responseData)
    })

    这样就完成了,如图:

  • OC 给 JS 传值

    还记得我们的那个btn吗,更刚才的正好相反:在btn方法中添加OC,而在JS中要加上初始化

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // JS中初始化
    <!-- OC向JS发消息,JS中的初始化 -->
    <!-- 匿名function对应于OC中所发消息 -->
    bridge.init(function(message, responseCallback) {
    log('JS中(从OC接收的消息)', message)
    var data = { '[[JS中]]接收到消息,并回复':'hello , OC' }
    log('[[JS中]]回复', data)
    responseCallback(data)
    })

    ---------------------

    // OC中btn
    NSLog(@" -- 发送消息 --");
    [self.bridge send:@"TED is goooood!" responseCallback:^(id responseData) {
    NSLog(@"what we receve: %@ ", responseData);
    }];

    结果:

调方法

先明确一点,如果JS -> OC, 说明OC中有方法,反之也一样

  • JS -> OC
    比如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // OC中
    [self.bridge registerHandler:@"ZXOCHandler" handler:^(id data, WVJBResponseCallback responseCallback) {

    NSLog(@"[OC中],JS传来的消息:%@", data);

    [self sendMessage:nil];
    responseCallback(@"[OC中],已收到");
    }];

    // JS中
    <!-- JS调方法,OC中已经的初始化 -->
    bridge.callHandler('ZXOCHandler', data, function(response) {
    log('[JS中] got response', response)
    })
  • OC -> JS
    更改OC中Btn点击的方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    // JS中初始化方法
    <!--注册 ZXJSHandler 方法-->
    bridge.registerHandler('ZXJSHandler', function(data, responseCallback) {
    log('[JS中],ZXJSHandler be called, withPra: %@', data)
    var backData = {'[JS中]':'ZXJSHandler be called'}
    responseCallback(backData)
    log('[JS中],ZXJSHandler be called, then responding:', backData)
    })

    ---------------------

    // OC的btn中调方法
    NSLog(@"-- 调用 ZXJSHandler --");
    [self.bridge callHandler:@"ZXJSHandler" data:@"[OC中]来自OC的问候" responseCallback:^(id responseData) {
    NSLog(@"ZXJSHandler的回复: %@", responseData);
    }];

就死这样的酸爽,就是这样的写意,这些足够满足日常需求了

现在回来看,其实所谓的通信传值,不就是调用对方的init方法吗?所以说2种其实是一回事儿

一点儿吭

在博主实际使用开发app的“邀你注册,给你红包”活动功能中,遇到过一个吭。当时同样的前端代码,在android是正常的,而在ios端无论如何都不运行,或者是偶尔正常,找了所有的问题

撕了不少b

都不觉得有问题

最后发现是webView的机制问题,webView打开一个url发生跳转时,跟安卓不同,是异步的,这就意味着如果有一次性的的链接,比如活动中生命周期唯一的优惠码,如果前端框架也是异步的就会发生永远也拿不到唯一的优惠码,显示的错误为已过期的提示,最终跟前端大哥商量他修改了代码,才搞好

所以🙏前端大哥和浩哥等几位的大哥的耐心与帮助,有些问题真不是自己一个人能搞定的