JS 与 OC 中的交互
现在移动端的业务大多与web 相互的交集,为了更好更快的配合线上的业务,web 混合 开发 是移动人员具备的基础能力 在这,我总结下 我从几家公司中自己所学习的web 和 oc 交互的知识:
UIWebVwe
UIWebView继承与UIView,因此,其初始化方法和一般的View一样,通过alloc和init进行初始化。
UIWebView 是用来加载加载网页数据的一个框。UIWebView可以用来加载pdf、word、doc 等等文件
本地加载一个html 文件
- (void)viewDidLoad {
[super viewDidLoad];
//加载本地文件
///UIKIT_EXTERN API_DEPRECATED("No longer supported; please adopt WKWebView.", ios(2.0, 12.0)) iOS 12之后UIwebView 即将被废弃
UIWebView * web = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
NSURL * url = [[NSBundle mainBundle] URLForResource:@"baidu.html" withExtension:nil];
NSURLRequest * request = [NSURLRequest requestWithURL:url];
[web loadRequest:request];
[self.view addSubview:web];
}
#pragma mark delegate
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
return YES;
}
-(void)webViewDidFinishLoad:(UIWebView *)webView
{
self.title = [webView stringByEvaluatingJavaScriptFromString:@"document.title"];
}
直接根据链接加载网页
[web loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"www.baidu.com" relativeToURL:nil]]];
或者说 你根绝html 内容 直接加载 (项目中 自己做一个图片加载链接地址 然后加载内容... ) 具体参照HTML标签去处理
[self.webView loadHTMLString:@"你所要表述的内容实质
" baseURL:nil];
再就是加载文件,比如 PDF Word文件等等 这些都是web 能做到的
例如
#pragma 以二进制数据的形式加载文件
- (void)loadDataFile {
// 最最常见的一种情况
// 打开IE,访问网站,提示你安装Flash插件
// 如果没有这个应用程序,是无法用UIWebView打开对应的文件的
// 应用场景:加载从服务器上下载的文件,例如pdf,或者word,图片等等文件
NSURL *fileURL = [[NSBundle mainBundle] URLForResource:@"iOS 7 Programming Cookbook.pdf" withExtension:nil];
NSURLRequest *request = [NSURLRequest requestWithURL:fileURL];
// 服务器的响应对象,服务器接收到请求返回给客户端的
NSURLResponse *respnose = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&respnose error:NULL];
NSLog(@"%@", respnose.MIMEType);
// 在iOS开发中,如果不是特殊要求,所有的文本编码都是用UTF8
// 先用UTF8解释接收到的二进制数据流
[self.webView loadData:data MIMEType:respnose.MIMEType textEncodingName:@"UTF8" baseURL:nil];
}
// 本地方法:
//从本地加载
NSString *thePath = [[NSBundle mainBundle] pathForResource:@"User_Guide" ofType:@"pdf"];
if (thePath) {
NSData *pdfData = [NSData dataWithContentsOfFile:thePath];
[self.webView loadData:pdfData MIMEType:@"application/pdf" textEncodingName:@"utf-8" baseURL:nil];
}
这个业务 楼主遇到过 做出的方式就是仿照微信去打开文件 然后去链接蓝牙设备 打印等等...
以上说述 都是webview的使用方式 那么 现在我就继续往下面走 代理方法什么的 我就不写了 毕竟相对来说都比较基础
UIWebview 交互JS
1如何处理 代码拦截
在iOS的工程代码中 web 和 js 的交互 主要的进行方式是在
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
这个代码中
NSLog(@"%@",request);
对request 对象进行打印 会发现这个reque 展示的是一个 路由
这个就是web的文件地址所在的地方
在此 就能做一个处理 就是 NSLog(@"schme ===== %@",request.URL.scheme);
在此,可以处理web 中 js 交互不存在的交互方法 做拦截 当然,从这个地方也可以制定自己的一套方案 想怎么玩就怎么玩 js 所有的响应 都会根据你的想法去执行。
2 js 与 oc 的交互
NSLog(@"%@",request.URL.pathComponents);
此处是对js文件里面的路径的信息处理
比如 在此处 我们传递一个字段 里面增加一个getsum的参数。
那么 在打印的地方就会出现
"/", getsum(1,3), Users, chenjiazhen, Library, Developer, CoreSimulator, Devices, "D3F41005-1A57-4DAF-B3CE-47A986C9B867", data, Containers, Bundle, Application, "B6FF5281-6954-45AB-935B-11626882C61B", "demo.app", "baidu.html"
类似于这样的一个信息数组,那么 就在getsum(1,3) 类似于这种调用方式 就会添加到这个信息数组中
就能拿到当前js 和 web 的交互数据了 然后 经过约定处理好后 oc 获取方法名 和 传递参数 使用 以下的代码 就能完成 js 调用 oc 的系统内容了
`
[self performSelector:NSSelectorFromString(@"xxx") withObject:@"数据内容" afterDelay:0];
`
3 oc 调用 js
emmmmmm... 这个我觉得没得必要详细的去总结 因为 之前已经在博客内容里面其实已经写到了
self.title = [webView stringByEvaluatingJavaScriptFromString:@"document.title"];
这个 就是 获取js 的系统方法的title名,当然 这里用的是最老套的方法 ,主要函数还是
stringByEvaluatingJavaScriptFromString
当然 可以根据内容继续拓展 比如你想通过 oc 调用 js的函数
以alert为例子
[webView stringByEvaluatingJavaScriptFromString:@"showAlert("你要来和我一起玩吗 ?")"];
这里 调用的就是js 的showAlert的方法 传递的信息技术括号内的内容
当然 如若 js 有数据信息返回 我们就如title的获取一样 用字符串接受 然后自己做处理就好了
JavaScriptCore
写到这个就是很牛逼了,因为 以上代码 太复杂 ,用这个 贼简单 讲讲使用:
`
JSContext * CONT = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
//创建一个全局的函数 也包括 调用js的方法参数
[CONT evaluateScript:@"var arr = ['haha','yes','baby']"];
//保存一段代码块
//当js 调用 方法的时候 这边就会处理 包括参数啊什么的
CONT[@"saveMyinfo"] = ^{
//获取参数
NSArray * ager = [JSContext currentArguments];
};
`
这里 缩减了很多的方法处理判断,然后 我们就是通过js 调用方法 在oc 中保存了一段代码块 ,js 调用 saveMyinfo 的时候,那么 这个信息就反馈在了oc 的代码中 我们可以获取到系统参数啊什么的,比以上 简介很多,目前 我所看到的很多关于 js调用oc 的桥接封装 都是这么处理的 。当然 调用js 就是如上 evaluateScript这个方法,我就不过多的描述了。
以上 都是UIWebView 那么继续...
WKWebView
不过多的介绍 iOS 都应该知道 这是Apple 对UIweb的优化
WKWebView:网页的渲染与展示
注意: #import
//初始化
_webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT) configuration:config];
// UI代理
_webView.UIDelegate = self;
// 导航代理
_webView.navigationDelegate = self;
// 是否允许手势左滑返回上一级, 类似导航控制的左滑返回
_webView.allowsBackForwardNavigationGestures = YES;
//可返回的页面列表, 存储已打开过的网页
WKBackForwardList * backForwardList = [_webView backForwardList];
// NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://www.chinadaily.com.cn"]];
// [request addValue:[self readCurrentCookieWithDomain:@"http://www.chinadaily.com.cn"] forHTTPHeaderField:@"Cookie"];
// [_webView loadRequest:request];
//页面后退
[_webView goBack];
//页面前进
[_webView goForward];
//刷新当前页面
[_webView reload];
NSString *path = [[NSBundle mainBundle] pathForResource:@"JStoOC.html" ofType:nil];
NSString *htmlString = [[NSString alloc]initWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
//加载本地html文件
[_webView loadHTMLString:htmlString baseURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]]];
WKWebViewConfiguration:为添加WKWebView配置信息
//创建网页配置对象
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
// 创建设置对象
WKPreferences *preference = [[WKPreferences alloc]init];
//最小字体大小 当将javaScriptEnabled属性设置为NO时,可以看到明显的效果
preference.minimumFontSize = 0;
//设置是否支持javaScript 默认是支持的
preference.javaScriptEnabled = YES;
// 在iOS上默认为NO,表示是否允许不经过用户交互由javaScript自动打开窗口
preference.javaScriptCanOpenWindowsAutomatically = YES;
config.preferences = preference;
// 是使用h5的视频播放器在线播放, 还是使用原生播放器全屏播放
config.allowsInlineMediaPlayback = YES;
//设置视频是否需要用户手动播放 设置为NO则会允许自动播放
config.requiresUserActionForMediaPlayback = YES;
//设置是否允许画中画技术 在特定设备上有效
config.allowsPictureInPictureMediaPlayback = YES;
//设置请求的User-Agent信息中应用程序名称 iOS9后可用
config.applicationNameForUserAgent = @"ChinaDailyForiPad";
//自定义的WKScriptMessageHandler 是为了解决内存不释放的问题
WeakWebViewScriptMessageDelegate *weakScriptMessageDelegate = [[WeakWebViewScriptMessageDelegate alloc] initWithDelegate:self];
//这个类主要用来做native与JavaScript的交互管理
WKUserContentController * wkUController = [[WKUserContentController alloc] init];
//注册一个name为jsToOcNoPrams的js方法
[wkUController addScriptMessageHandler:weakScriptMessageDelegate name:@"jsToOcNoPrams"];
[wkUController addScriptMessageHandler:weakScriptMessageDelegate name:@"jsToOcWithPrams"];
config.userContentController = wkUController;
WKUserContentController:这个类主要用来做native与JavaScript的交互管理
//这个类主要用来做native与JavaScript的交互管理
WKUserContentController * wkUController = [[WKUserContentController alloc] init];
//注册一个name为jsToOcNoPrams的js方法,设置处理接收JS方法的代理
[wkUController addScriptMessageHandler:self name:@"jsToOcNoPrams"];
[wkUController addScriptMessageHandler:self name:@"jsToOcWithPrams"];
config.userContentController = wkUController;
//用完记得移除
//移除注册的js方法
[[_webView configuration].userContentController removeScriptMessageHandlerForName:@"jsToOcNoPrams"];
[[_webView configuration].userContentController removeScriptMessageHandlerForName:@"jsToOcWithPrams"];
WKScriptMessageHandler:这个协议类专门用来处理监听JavaScript方法从而调用原生OC方法,和WKUserContentController搭配使用。
注意:遵守WKScriptMessageHandler协议,代理是由WKUserContentControl设置
//通过接收JS传出消息的name进行捕捉的回调方法
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
NSLog(@"name:%@\\\\n body:%@\\\\n frameInfo:%@\\\\n",message.name,message.body,message.frameInfo);
//用message.body获得JS传出的参数体
NSDictionary * parameter = message.body;
//JS调用OC
if([message.name isEqualToString:@"jsToOcNoPrams"]){
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"js调用到了oc" message:@"不带参数" preferredStyle:UIAlertControllerStyleAlert];
[alertController addAction:([UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
}])];
[self presentViewController:alertController animated:YES completion:nil];
}else if([message.name isEqualToString:@"jsToOcWithPrams"]){
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"js调用到了oc" message:parameter[@"params"] preferredStyle:UIAlertControllerStyleAlert];
[alertController addAction:([UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
}])];
[self presentViewController:alertController animated:YES completion:nil];
}
}
以上就是WKweb的一些介绍 和 详细的使用方式了 ... 写这么多 感觉脑袋都要爆炸了 ,我在总结下
oc 调用 js
[_webView evaluateJavaScript:@"你所需要的传递的参数 或者你响应的方法 " completionHandler:^(id _Nullable data, NSError * _Nullable error) {
//下面是返回的回调信息
NSLog(@"我是回调信息");
}];
js 调用 oc
//通过接收JS传出消息的name进行捕捉的回调方法
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
NSLog(@"name:%@\\\\n body:%@\\\\n frameInfo:%@\\\\n",message.name,message.body,message.frameInfo);
//用message.body获得JS传出的参数体
NSDictionary * parameter = message.body;
//JS调用OC
if([message.name isEqualToString:@"jsToOcNoPrams"]){
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"js调用到了oc" message:@"不带参数" preferredStyle:UIAlertControllerStyleAlert];
[alertController addAction:([UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
}])];
[self presentViewController:alertController animated:YES completion:nil];
}else if([message.name isEqualToString:@"jsToOcWithPrams"]){
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"js调用到了oc" message:parameter[@"params"] preferredStyle:UIAlertControllerStyleAlert];
[alertController addAction:([UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
}])];
[self presentViewController:alertController animated:YES completion:nil];
}
}
以上就是业务中常用到得js oc 交互的总结,目前网上 很多的第三方封装介绍对这些函数信息的封装处理后 直接block 回调封装的,如果我的总结 能给你帮助,帮忙点个喜欢 谢谢
武汉的天气太热 .... 我要去冲澡