iOS下JS与OC互相调用(一)--UIWebView 拦截URL
- 1.在JS 中做一次URL跳转,然后在OC中拦截跳转。(这里分为UIWebView 和 WKWebView两种,去年因为还要兼容iOS 6,所以没办法只能采用UIWebView来做。)
- 2.利用WKWebView 的MessageHandler。
- 3.利用系统库JavaScriptCore,来做相互调用。(iOS 7推出的)
- 4.利用第三方库WebViewJavascriptBridge。
- 5.利用第三方cordova库,以前叫PhoneGap。(这是一个库平台的库)
- 6.当下盛行的React Native。
我去年也写过一个相互调用的总结:iOS下JS与原生OC互相调用(总结)。
写的比较粗糙,因此准备新开一个目录专题来记录JS 与原生交互的处理方式。只是记录JS与OC交互的多种方式,大家可以根据实际情况和场景选择适合自己的方式。
今天就详细的介绍一下使用UIWebView拦截URL 的方式来实现JS与OC 的交互。
为什么不使用第三方库或者RAC呢?
因为就相互调用的接口使用的非常少啊,就那么三两个,完全没必要使用牛刀啊。

UIWebView 拦截URL
我之前就使用的是UIWebView + 拦截URL 的方式实现的JS与OC 交互。
原因是因为要兼容iOS 6。
1.创建UIWebView,并加载本地HTML。
加载本地HTML的目的是便于自己写JS调用做测试,最终肯定还是加载网络HTML。
self.webView = [[UIWebView alloc] initWithFrame:self.view.frame];self.webView.delegate = self;NSURL *htmlURL = [[NSBundle mainBundle] URLForResource:@"index.html" withExtension:nil];
// NSURL *htmlURL = [NSURL URLWithString:@"http://www.baidu.com"];NSURLRequest *request = [NSURLRequest requestWithURL:htmlURL];// 如果不想要webView 的回弹效果self.webView.scrollView.bounces = NO;// UIWebView 滚动的比较慢,这里设置为正常速度self.webView.scrollView.decelerationRate = UIScrollViewDecelerationRateNormal;[self.webView loadRequest:request];[self.view addSubview:self.webView];
本地的HTML里,我定义了几个按钮,来触发调用原生的方法,然后再将执行结果回调到js 里。
<input type="button" value="扫一扫" onclick="scanClick()" />
<input type="button" value="获取定位" onclick="locationClick()" />
<input type="button" value="修改背景色" onclick="colorClick()" />
<input type="button" value="分享" onclick="shareClick()" />
<input type="button" value="支付" onclick="payClick()" />
<input type="button" value="摇一摇" onclick="shake()" />
<input type="button" value="返回" onclick="goBack()" />// js 就列几个比较有代表性的functions:function loadURL(url) {var iFrame;iFrame = document.createElement("iframe");iFrame.setAttribute("src", url);iFrame.setAttribute("style", "display:none;");iFrame.setAttribute("height", "0px");iFrame.setAttribute("width", "0px");iFrame.setAttribute("frameborder", "0");document.body.appendChild(iFrame);// 发起请求后这个iFrame就没用了,所以把它从dom上移除掉iFrame.parentNode.removeChild(iFrame);iFrame = null;
}function asyncAlert(content) {setTimeout(function(){alert(content);},1);
}function locationClick() {loadURL("haleyAction://getLocation");
}function setLocation(location) {asyncAlert(location);document.getElementById("returnValue").value = location;
}
虽然HTML 内容很少,但是还有不少学问:
1.为什么自定义一个
loadURL
方法,不直接使用window.location.href
?
答:因为如果当前网页正使用window.location.href
加载网页的同时,调用window.location.href
去调用OC原生方法,会导致加载网页的操作被取消掉。
同样的,如果连续使用window.location.href
执行两次OC原生调用,也有可能导致第一次的操作被取消掉。所以我们使用自定义的loadURL
,来避免这个问题。
loadURL
的实现来自关于UIWebView和PhoneGap的总结一文。
2.为什么loadURL 中的链接,使用统一的scheme?
答:便于在OC 中做拦截处理,减少在JS中调用一些OC 没有实现的方法时,webView 做跳转。因为我在OC 中拦截URL 时,根据scheme (即haleyAction
)来区分是调用原生的方法还是正常的网页跳转。然后根据host(即//后的部分getLocation
)来区分执行什么操作。
3.为什么自定义一个asyncAlert
方法?
答:因为有的JS调用是需要OC 返回结果到JS的。stringByEvaluatingJavaScriptFromString
是一个同步方法,会等待js 方法执行完成,而弹出的alert 也会阻塞界面等待用户响应,所以他们可能会造成死锁。导致alert 卡死界面。如果回调的JS 是一个耗时的操作,那么建议将耗时的操作也放入setTimeout
的function
中。
2.拦截 URL
UIWebView 有一个代理方法,可以拦截到每一个链接的Request。return YES,webView 就会加载这个链接;return NO,webView 就不会加载这个连接。我们就在这个拦截的代理方法中处理自己的URL。
这是我的示例代码:
#pragma mark - UIWebViewDelegate
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{NSURL *URL = request.URL;NSString *scheme = [URL scheme];if ([scheme isEqualToString:@"haleyaction"]) {[self handleCustomAction:URL];return NO;}return YES;
}
这里通过scheme,来拦截掉自定义的URL 就非常容易了,如果不同的方法使用不同的scheme,那么判断起来就非常的麻烦。
然后,看看我的处理连接的方法:
#pragma mark - private method
- (void)handleCustomAction:(NSURL *)URL
{NSString *host = [URL host];if ([host isEqualToString:@"scanClick"]) {NSLog(@"扫一扫");} else if ([host isEqualToString:@"shareClick"]) {[self share:URL];} else if ([host isEqualToString:@"getLocation"]) {[self getLocation];} else if ([host isEqualToString:@"setColor"]) {[self changeBGColor:URL];} else if ([host isEqualToString:@"payAction"]) {[self payAction:URL];} else if ([host isEqualToString:@"shake"]) {[self shakeAction];} else if ([host isEqualToString:@"goBack"]) {[self goBack];}
}
顺便看一下如何将结果回调到JS中:
- (void)getLocation
{// 获取位置信息// 将结果返回给jsNSString *jsStr = [NSString stringWithFormat:@"setLocation('%@')",@"广东省深圳市南山区学府路XXXX号"];[self.webView stringByEvaluatingJavaScriptFromString:jsStr];
}
当然,有时候我们在JS中调用OC 方法的时候,也需要传参数到OC 中,怎么传呢?
就像一个get 请求一样,把参数放在后面:
function shareClick() {loadURL("haleyAction://shareClick?title=测试分享的标题&content=测试分享的内容&url=http://www.baidu.com");
}
那么如果获取到这些参数呢?
所有的参数都在URL的query中,先通过&
将字符串拆分,在通过=
把参数拆分成key 和实际的值。下面有示例代码:
- (void)share:(NSURL *)URL
{NSArray *params =[URL.query componentsSeparatedByString:@"&"];NSMutableDictionary *tempDic = [NSMutableDictionary dictionary];for (NSString *paramStr in params) {NSArray *dicArray = [paramStr componentsSeparatedByString:@"="];if (dicArray.count > 1) {NSString *decodeValue = [dicArray[1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];[tempDic setObject:decodeValue forKey:dicArray[0]];}}NSString *title = [tempDic objectForKey:@"title"];NSString *content = [tempDic objectForKey:@"content"];NSString *url = [tempDic objectForKey:@"url"];// 在这里执行分享的操作// 将分享结果返回给jsNSString *jsStr = [NSString stringWithFormat:@"shareResult('%@','%@','%@')",title,content,url];[self.webView stringByEvaluatingJavaScriptFromString:jsStr];
}
3. OC调用JS方法
关于将OC 执行结果返回给JS 需要注意的是:
如果回调执行的JS 方法带参数,而参数不是字符串时,不要加
单引号
,否则可能导致调用JS 方法失败。比如我这样的:
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:userProfile options:NSJSONWritingPrettyPrinted error:nil]; NSString *jsonStr = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; NSString *jsStr = [NSString stringWithFormat:@"loginResult('%@',%@)",type, jsonStr]; [_webView stringByEvaluatingJavaScriptFromString:jsStr];
如果第二个参数用单引号包起来,就会导致JS端的loginResult不会调用。
另外,利用[webView stringByEvaluatingJavaScriptFromString:@"var arr = [3, 4, 'abc'];"];
,可以往HMTL的JS环境中插入全局变量、JS方法等。
相关文章:
AI换脸鉴别率超99.6%,微软用技术应对虚假信息
来源 | 微软亚洲研究院AI头条(ID:MSRAsia)近日社交网络上爆红的一款换脸应用,让许多普通用户体验到了跟爱豆同框、与偶像飙戏的快乐,也因数据使用带来的问题陷入了舆论的漩涡——除了用户隐私保障,如何辨别和处理换脸应…

使用Apache Tiles3.x构建界面布局(一)
Tiles是一个免费的开源模板Java应用程序的框架。基于复合模式简化的用户界面的构建。对于复杂的网站仍是最简单、最优雅的方式与任何MVC技术一起工作。Struts2对Tiles提供了支持,如今Tiles发展已有13个年头,成为Apache的一个独立项目,我们可以…

iOS下JS与OC互相调用(二)--WKWebView 拦截URL
在上篇文章中讲述了使用UIWebView拦截URL的方式来处理JS与OC交互。 由于UIWebView比较耗内存,性能上不太好,而苹果在iOS 8中推出了WKWebView。 同样的用WKWebView也可以拦截URL,做JS 与OC交互。关于WKWebView与UIWebView的对比,大…
基于模型的强化学习比无模型的强化学习更好?错!
作者 | Carles Gelada and Jacob Buckman编辑 | DeepRL来源 | 深度强化学习实验室(ID:Deep-RL)【导读】许多研究人员认为,基于模型的强化学习(MBRL)比无模型的强化学习(MFRL)具有更高的样本效率。但是&…

程序员的自我修养--链接、装载与库笔记:内存
1. 程序的内存布局 现代的应用程序都运行在一个内存空间里,在32位的系统里,这个内存空间拥有4GB(2的32次方)的寻址能力。应用程序可以直接使用32位的地址进行寻址,这被称为平坦(flat)的内存模型。在平坦的内存模型中,整个内存是一…

【Away3D代码解读】(四):主要模块简介
数据模块: Away3D中最核心的数据类是Mesh类,我们先看看Mesh类的继承关系: NamedAssetBase:为对象提供id和name属性,是Away3D大部分类的基类; Object3D:3D对象基类,提供方便操作3D对象…

程序员的自我修养--链接、装载与库笔记:运行库
1. 入口函数和程序初始化 程序从main开始吗?:操作系统装载程序之后,首先运行的代码并不是main的第一行,而是某些别的代码,这些代码负责准备好main函数执行所需要的环境,并且负责调用main函数,这…

iOS下JS与OC互相调用(三)--MessageHandler
使用WKWebView的时候,如果想要实现JS调用OC方法,除了拦截URL之外,还有一种简单的方式。那就是利用WKWebView的新特性MessageHandler来实现JS调用原生方法。 MessageHandler 是什么? WKWebView 初始化时,有一个参数叫…
北大教授张大庆:无线感知,让你变老也优雅
受访者 | 张大庆记者 | 胡巍巍出品 | CSDN(ID:CSDNnews)在国内高校中,北大的校庆日很特殊——5月4日。这一天,也是青年节。北大,是五四运动的策源地。100年来,“爱国、进步、民主、科学”的五四…

总结 20 个开发细节
2019独角兽企业重金招聘Python工程师标准>>> 1:提交到SVN的代码必须有提交备注,以便于以后查看。 2:如考虑页面缓存,可以在路径后增加随机数:url "&TimeS" Math.random();。 3:…

程序员的自我修养--链接、装载与库笔记:系统调用与API
系统调用(System Call)是应用程序(运行库也是应用程序的一部分)与操作系统内核之间的接口,它决定了应用程序是如何与内核打交道的。无论程序是直接进行系统调用,还是通过运行库,最终还是会到达系统调用这个层面上。 1. 系统调用介绍 什么是…

iOS下JS与OC互相调用(四)--JavaScriptCore
前面讲完拦截URL的方式实现JS与OC互相调用,终于到JavaScriptCore了。它是从iOS7开始加入的,用 Objective-C 把 WebKit 的 JavaScript 引擎封装了一下,提供了简单快捷的方式与JavaScript交互。 关于JavaScriptCore的使用有两篇很好的文章&…
围巾都这么黑科技了,是我见识少了
有一个永恒的话题:北方冷一点还是南方冷一点?答案是:哪里都冷!冬天最痛苦的莫过于走出空调房——刺骨的风直直的从领口处灌进去那叫一个“透心凉,心飞扬”缠了好几圈的大围巾却根本没什么保暖效果每当这时候࿰…

【教程】【FLEX】#004 反射机制
总结: 目前用到反射的主要有两个方法 1. getDefinitionByName //根据类名,返回对象(反射实例化对象) 2. describeType //根据对象,返回XML格式的属性,方法等信息(反射得到…

iOS下JS与OC互相调用(五)--UIWebView + WebViewJavascriptBridge
WebViewJavascriptBridge是一个有点年代的JS与OC交互的库,使用该库的著名应用还挺多的,目前这个库有7000star。我去翻看了它的第一版本已经是4年前了,在版本V4.1.4以及之前,该库只有一个类和一个js 的txt文件,所以旧版…

OpenCV代码提取:Windows上通过DShow获取Camera视频
在OpenCV 3.1中获取视频的模块在videoio(video input and output module)中,调用VideoCapture类接口,除了videoio模块外还依赖core、highgui、imgproc、imgcodecs四个模块,而OpenCV 2.4.13.6仅需要core、highgui、imgproc三个模块。3.1中的vi…
迁移学习与图神经网络“合力”模型:用DoT-GNN克服组重识别难题
作者 | Ziling Huang、Zheng Wang、Wei Hu、Chia-Wen Lin、Shin’ichi Satoh译者 | 刘畅编辑 | Jane出品 | AI科技大本营(ID:rgznai100)【导读】目前,大多数行人重识别(ReID)方法主要是从收集的单个人图像数…

struts2 select 默认选中
jsp:<s:select list"#{1:男,2:女}" name"sex"/> action:private String sex;sex属性有get/set方法。在业务方法中设置sex "2";select会默认选中。

通过Windows DShow获取设备名、支持的编解码及视频size列表实现
之前在https://blog.csdn.net/fengbingchun/article/details/102641967中介绍过通过DShow获取Camera视频的实现,即调用VideoCapture类。在OpenCV的VideoCapture类中并没有提供获取Camera设备列表、支持的编解码类型列表及支持的video size列表接口,这里基…
15篇论文全面概览BERT压缩方法
作者 | Mitchell A. Gordon译者 | 孙薇出品 | AI科技大本营(ID:rgznai100)模型压缩可减少受训神经网络的冗余——由于几乎没有BERT或者BERT-Large模型可用于GPU及智能手机上,这一点就非常有用了。另外,内存与推理速度的提高也能节…

iOS下JS与OC互相调用(七)--Cordova 基础
Cordova 简介 在介绍Cordova之前,必须先提一下PhoneGap。PhoneGap 是Nitobi软件公司2008年推出的一个框架,旨在弥补web 和iOS 之间的不足,使得web 和 iPhone SDK 之间的交互更容易。后来又加入了Android SDK 和BlackBerry SDK,再然…

在linux上MySQL的三种安装方式
安装MySQL的方式常见的有三种:方式一:rpm安装(1) 操作系统发行商提供的(2) MySQL官方提供的(版本更新,修复了更多常见BUG)www.mysql.com/downloads关于MySQL中rpm包类型的介绍:MySQL-client 客户端…

通过libjpeg-turbo实现对jpeg图像的解码
之前在https://blog.csdn.net/fengbingchun/article/details/89715416中介绍过通过libjpeg-turbo接口实现将数据编码或压缩成jpeg数据并通过FILE的fwrite接口将其直接保存成*.jpg图像,当时用的是libjpeg的接口,其实还可以使用turbojpeg api的接口即tjCom…
AI+大数据顶级技术盛会开幕在即,6.6折特惠票限时抢购
2019年12月5-7日,由中国计算机学会主办,CCF 大数据专家委员会承办,CSDN、中科天玑数据科技股份有限公司协办的中国大数据技术大会(BDTC 2019)将于北京长城饭店隆重举行。届时,超过百位顶尖技术专家将齐聚于…

iOS下JS与OC互相调用(八)--Cordova详解+实战
1.新建工程,添加Cordova 关键类 我这里用Xcode 8 新建了一个工程,叫 JS_OC_Cordova,然后将Cordova关键类添加进工程。 有哪些关键类呢? 这里添加config.xml 、Private 和 Public 两个文件夹里的所有文件。工程目录结构如下: 然后…

iOS多线程编程之NSOperation和NSOperationQueue的使用
使用 NSOperation的方式有两种, 一种是用定义好的两个子类: NSInvocationOperation 和 NSBlockOperation。 另一种是继承NSOperation 如果你也熟悉Java,NSOperation就和java.lang.Runnable接口很相似。和Java的Runnable一样,NSOpe…

Swift - 使用SwiftHTTP通过HTTPS进行网络请求,及证书的使用
(本文代码已升级至Swift3)一,证书的生成,以及服务器配置参考我前面写的这篇文章:Tomcat服务器配置https双向认证(使用keytool生成证书)文章详细介绍了HTTPS,SSL/TLS。还有使用key to…

Linux下通过v4l2获取视频设备名、支持的编解码及视频size列表实现
早些时候给出了在Windows下通过dshow获取视频设备信息的实现,包括获取视频设备名、获取每种视频设备支持的编解码格式列表、每种编解码格式支持的video size列表,见:https://blog.csdn.net/fengbingchun/article/details/102806822 下面给出…
12种主流编程语言输出“ Hello World ”,把我给难住了!
作为一名程序员,在初步学习编程想必都绕不开一个最为基础的入门级示例“Hello World”,那么,你真的了解各个语言“Hello World”的正确写法吗?在我们刚开始打开编程世界的时候,往往写的第一个程序都是简单的文本输出&a…

军哥lnmp一键安装包nginx支持pathinfo配置
ssh里执行:cat > /usr/local/nginx/conf/pathinfo.conf << EOF set $real_script_name $fastcgi_script_name; if ($fastcgi_script_name ~ "(.?\.php)(/.*)") { set $real_script_name $1; set $path_info $2; } fastcgi_param SCRIPT_FILENAM…