博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
iOS Hybrid开发演进
阅读量:6071 次
发布时间:2019-06-20

本文共 4873 字,大约阅读时间需要 16 分钟。

Web技术相对于Native来说有很多优势,比如:跨端(浏览器、Android、iOS)、排版更灵活、实时生效等。所以,在开发中我们经常会采用一些Web页面嵌入到APP中。

这样,就引入了web与Native的交互,往往也就是JavaScript与Native的交互。

JS与Native的交互,可以大致分为:Native调用JS、JS调用Native。

Native调用JS

Native调用JS比较简单

//UIWebView- (nullable NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script;//WKWebView- (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^ _Nullable)(_Nullable id, NSError * _Nullable error))completionHandler;复制代码

注意:

  • UIWebView执行JS是同步的,在WKWebView中是异步的。
  • UIWebView返回值只支持可String化的基本类型,并不支持集合类型(Array、Dictionary)和对象。
  • WKWebView执行JS的回调Block中支持集合类型和对象,也支持可String化的基本类型。
h5代码
	WKWebView    
复制代码
Native代码
//UIWebViewNSString *str = [self.webView stringByEvaluatingJavaScriptFromString:@"methodA('zhangsan', '123456')"];NSLog(@"str");//WKWebView[self.webView evaluateJavaScript:@"methodA('zhangsan', '123456')" completionHandler:^(id _Nullable value, NSError * _Nullable error) {    if (error) {        NSLog(@"%@", error);        return ;    }    NSLog(@"%@", value);}];复制代码

JS调用Native

其实,JS调用Native的交互经历过几个阶段。

iOS7之前

iOS7之前,JS想要调用Native时主动触发加载一个新的url。我们通过拦截URL通过提前约定的协议来判断是否为调用原生功能,用这种方式来处理JS对Native的调用。

JS端主要通过window.location.assign来触发新的加载。

iOS中在- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType中针对URL做判断。

JS代码
	WKWebView	
复制代码
OC代码
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {    NSString *urlPath = [request.URL absoluteString];    /*     * 与Web端协商定义交互协议 scheme://function_name?para1=value1&para2=value2&para3=value3&callback=callback_value     *  scheme为native时,是要与原生进行交互。     *  function_name指定要调用原生的什么功能。     *  para1是参数名称,value1是参数值     *  callback是原生执行完后对js的回调     */    if ([urlPath hasPrefix:@"native://"]) {        urlPath = [urlPath substringFromIndex:@"native://".length];        NSArray *questionMarkArray = [urlPath componentsSeparatedByString:@"?"];        NSString *funcName;        NSArray *paraArray;        if (questionMarkArray.count > 0) {            funcName = [questionMarkArray firstObject];            if (questionMarkArray.count > 1) {                // 从问号后还是都认定为参数                NSString *paraStr =  [urlPath substringFromIndex:funcName.length + 1];                paraArray = [paraStr componentsSeparatedByString:@"&"];            }        }                // funcname 匹配        if ([funcName isEqualToString:@"func1"]) {                    } else if ([funcName isEqualToString:@"func2"]) {                    } else if ([funcName isEqualToString:@"func3"]) {                    } else {                    }                return NO;    } else {        return YES;    }}复制代码

iOS7

iOS7开始,系统公开了JavaScriptCore框架,我们可以基于此来进行JS与Natvie的交互。

插播Javascript的调试方法(我们可以在Mac上调试JS代码)。

Safari的偏好设置中勾选底部的在菜单栏中显示“开发”菜单,然后Safari的菜单栏中就多出了开发菜单,当webview加载完h5后就可以选择对应的模拟器下对应的应用进行web调试。详细步骤和真机的调试方法请自行Google。

iOS7中通常采用的方式是拿到JSContext,然后将OC的方法或对象注入到JS中。

- (void)webViewDidFinishLoad:(UIWebView *)webView {    self.jsContext = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];        // JS的异常回调    self.jsContext.exceptionHandler = ^(JSContext *context, JSValue *exception) {        NSLog(@"%@", exception);    };        // 注入方法    self.jsContext[@"addNum"] = ^(int a, int b) {        return a + b;    };        // 注入对象    NSDictionary *dict = @{@"aaa" : @"aaa", @"bbb" : @"bbb"};    self.jsContext[@"dict"] = [JSValue valueWithObject:dict inContext:self.jsContext];}复制代码

然后在JS中就可以调用相应的对象和方法,调用方式和调用原生的方法或对象一致。

function callByContext() {    
var num = addNum(5, 8); console.log(num);
console.log(dict);}复制代码

iOS8 WKWebView

UIWebView有很多性能问题,所以苹果在iOS8中引入了新的浏览器组件WKWebView。

并且在iOS12后苹果废弃了UIWebView,所以请同学们务必赶紧升级到WKWebView!!!

在WKWebView的交互中,要使用WKUserContentController。在WKWebView构建的时候,需要传入WKWebViewConfiguration,而WKWebViewConfiguration可以添加WKUserContentController为ScriptMessageHandler。

WKUserContentController *userContent = [[WKUserContentController alloc] init];//伪代码[userContent addScriptMessageHandler:id
name:@"MyNative"]; WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];config.userContentController = userContent; WKWebView *webView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:config];复制代码

handler 对象需要实现WKScriptMessageHandler协议,当 JS 端通过 window.webkit.messageHandlers 发送 Native 消息时,handler 对象的协议方法被调用,通过协议方法的相关参数传值。

#pragma mark - WKScriptMessageHandler- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {}复制代码

JS调用iOS的方法

// Javascriptfunction callNative() {  window.webkit.messageHandlers.MyNative.postMessage('body');}复制代码

相关的JS和iOS代码已上传至GitHub(),可自行下载和调试。

转载于:https://juejin.im/post/5d06fca4518825498b57dff0

你可能感兴趣的文章
ceph官方文档笔记(一)
查看>>
django简单用户登陆验证
查看>>
在Mac OS X中安装MySQL
查看>>
微信图片放大
查看>>
MySQL_join开发技巧
查看>>
centOS6.3下lamp搭建(提供全套软件包)
查看>>
数组拷贝
查看>>
cut
查看>>
Xen400培训-XenServer最佳实践
查看>>
直接在终端创建文件并写入内容,不用vi ,vim等编辑器来完成
查看>>
07-k8s-dns
查看>>
k8s-12-pod的健康检查
查看>>
Sublime Text 2 - 性感无比的代码编辑器!程序员必备神器!
查看>>
Visual Studio 2010更改颜色背景的方法
查看>>
Android 中 ListView 分页加载数据
查看>>
jMeter入门实例
查看>>
清除历史记录
查看>>
Linux下如何解压.tar.bz2格式的压缩包
查看>>
centos6.6 安装 glances
查看>>
Mybatis 动态SQL
查看>>