网络 webView 与 JS的交互

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 展示的是一个 路由
{ URL: file:///Users/chenjiazhen/Library/Developer/CoreSimulator/Devices/D3F41005-1A57-4DAF-B3CE-47A986C9B867/data/Containers/Bundle/Application/BAF7F1D0-DCE6-4388-B810-6929B34058FA/demo.app/baidu.html }
这个就是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 回调封装的,如果我的总结 能给你帮助,帮忙点个喜欢 谢谢

武汉的天气太热 .... 我要去冲澡

你可能感兴趣的:(网络 webView 与 JS的交互)