内容简介:Web技术相对于Native来说有很多优势,比如:跨端(浏览器、Android、iOS)、排版更灵活、实时生效等。所以,在开发中我们经常会采用一些Web页面嵌入到APP中。这样,就引入了web与Native的交互,往往也就是JavaScript与Native的交互。Native调用JS比较简单
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代码
<!DOCTYPE html> <html> <head> <title>WKWebView</title> <meta charset="UTF-8" /> <script type="text/javascript"> function methodA(username, password) { console.log("Hello, I am methodA"); let dict = { "username" : username, "password" : password }; return "username: " + username + ", password: " + password; <!--return dict;--> <!--return ["A", "B"];--> } </script> </head> <body> </body> </html> 复制代码
Native代码
//UIWebView NSString *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代码
<!DOCTYPE html> <html> <head> <title>WKWebView</title> <meta charset="UTF-8" /> <script type="text/javascript"> function callNative() { window.location.assign("native://func1?name=zhangsan&password=123456"); } </script> </head> <body> <button onClick="callNative()">CallNative</button> </body> </html> 复制代码
OC代码
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { NSString *urlPath = [request.URL absoluteString]; /* * 与Web端协商定义交互协议 scheme://function_name?para1=value1¶2=value2¶3=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() { <!-- addNum为原生向JS注入的方法 --> var num = addNum(5, 8); console.log(num); <!-- dict为原生向JS注入的对象 --> 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<WKScriptMessageHandler> name:@"MyNative"]; WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init]; config.userContentController = userContent; WKWebView *webView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:config]; 复制代码
handler 对象需要实现指定协议,实现指定的协议方法,当 JS 端通过 window.webkit.messageHandlers 发送 Native 消息时,handler 对象的协议方法被调用,通过协议方法的相关参数传值。
#pragma mark - WKScriptMessageHandler - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {} 复制代码
JS调用iOS的方法
// Javascript function callNative() { window.webkit.messageHandlers.MyNative.postMessage('body'); } 复制代码
相关的JS和iOS代码已上传至GitHub( github.com/NewFarmer21… ),可自行下载和调试。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- SQL 开发任务超 50% !滴滴实时计算的演进与优化
- Docker快速搭建一套PHP、Nginx、MySQL、Redis、Xdebug、Memcached 开发环境并演进
- Spring核心技术原理-(2)-通过Web开发演进过程了解一下为什么要有Spring AOP?
- vue状态管理演进
- 集群调度系统的演进
- 服务端架构演进
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。