网络 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:@"<p>你所要表述的内容实质</p>" 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 展示的是一个 路由
<NSMutableURLRequest: 0x600001354220> { 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 <WebKit/WebKit.h>
     //初始化
       _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 回调封装的,如果我的总结 能给你帮助,帮忙点个喜欢 谢谢

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

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 230,321评论 6 543
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 99,559评论 3 429
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 178,442评论 0 383
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 63,835评论 1 317
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 72,581评论 6 412
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 55,922评论 1 328
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 43,931评论 3 447
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 43,096评论 0 290
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 49,639评论 1 336
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 41,374评论 3 358
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 43,591评论 1 374
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 39,104评论 5 364
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 44,789评论 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 35,196评论 0 28
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 36,524评论 1 295
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 52,322评论 3 400
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 48,554评论 2 379

推荐阅读更多精彩内容