当前位置: 首页 > 编程日记 > 正文

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 是一个耗时的操作,那么建议将耗时的操作也放入setTimeoutfunction 中。

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头条&#xff08;ID:MSRAsia&#xff09;近日社交网络上爆红的一款换脸应用&#xff0c;让许多普通用户体验到了跟爱豆同框、与偶像飙戏的快乐&#xff0c;也因数据使用带来的问题陷入了舆论的漩涡——除了用户隐私保障&#xff0c;如何辨别和处理换脸应…

使用Apache Tiles3.x构建界面布局(一)

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

iOS下JS与OC互相调用(二)--WKWebView 拦截URL

在上篇文章中讲述了使用UIWebView拦截URL的方式来处理JS与OC交互。 由于UIWebView比较耗内存&#xff0c;性能上不太好&#xff0c;而苹果在iOS 8中推出了WKWebView。 同样的用WKWebView也可以拦截URL&#xff0c;做JS 与OC交互。关于WKWebView与UIWebView的对比&#xff0c;大…

基于模型的强化学习比无模型的强化学习更好?错!

作者 | Carles Gelada and Jacob Buckman编辑 | DeepRL来源 | 深度强化学习实验室&#xff08;ID:Deep-RL)【导读】许多研究人员认为&#xff0c;基于模型的强化学习&#xff08;MBRL&#xff09;比无模型的强化学习&#xff08;MFRL&#xff09;具有更高的样本效率。但是&…

程序员的自我修养--链接、装载与库笔记:内存

1. 程序的内存布局 现代的应用程序都运行在一个内存空间里&#xff0c;在32位的系统里&#xff0c;这个内存空间拥有4GB(2的32次方)的寻址能力。应用程序可以直接使用32位的地址进行寻址&#xff0c;这被称为平坦(flat)的内存模型。在平坦的内存模型中&#xff0c;整个内存是一…

【Away3D代码解读】(四):主要模块简介

数据模块&#xff1a; Away3D中最核心的数据类是Mesh类&#xff0c;我们先看看Mesh类的继承关系&#xff1a; NamedAssetBase&#xff1a;为对象提供id和name属性&#xff0c;是Away3D大部分类的基类&#xff1b; Object3D&#xff1a;3D对象基类&#xff0c;提供方便操作3D对象…

程序员的自我修养--链接、装载与库笔记:运行库

1. 入口函数和程序初始化 程序从main开始吗&#xff1f;&#xff1a;操作系统装载程序之后&#xff0c;首先运行的代码并不是main的第一行&#xff0c;而是某些别的代码&#xff0c;这些代码负责准备好main函数执行所需要的环境&#xff0c;并且负责调用main函数&#xff0c;这…

iOS下JS与OC互相调用(三)--MessageHandler

使用WKWebView的时候&#xff0c;如果想要实现JS调用OC方法&#xff0c;除了拦截URL之外&#xff0c;还有一种简单的方式。那就是利用WKWebView的新特性MessageHandler来实现JS调用原生方法。 MessageHandler 是什么&#xff1f; WKWebView 初始化时&#xff0c;有一个参数叫…

北大教授张大庆:无线感知,让你变老也优雅

受访者 | 张大庆记者 | 胡巍巍出品 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09;在国内高校中&#xff0c;北大的校庆日很特殊——5月4日。这一天&#xff0c;也是青年节。北大&#xff0c;是五四运动的策源地。100年来&#xff0c;“爱国、进步、民主、科学”的五四…

总结 20 个开发细节

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

程序员的自我修养--链接、装载与库笔记:系统调用与API

系统调用(System Call)是应用程序(运行库也是应用程序的一部分)与操作系统内核之间的接口&#xff0c;它决定了应用程序是如何与内核打交道的。无论程序是直接进行系统调用&#xff0c;还是通过运行库&#xff0c;最终还是会到达系统调用这个层面上。 1. 系统调用介绍 什么是…

iOS下JS与OC互相调用(四)--JavaScriptCore

前面讲完拦截URL的方式实现JS与OC互相调用&#xff0c;终于到JavaScriptCore了。它是从iOS7开始加入的&#xff0c;用 Objective-C 把 WebKit 的 JavaScript 引擎封装了一下&#xff0c;提供了简单快捷的方式与JavaScript交互。 关于JavaScriptCore的使用有两篇很好的文章&…

围巾都这么黑科技了,是我见识少了

有一个永恒的话题&#xff1a;北方冷一点还是南方冷一点&#xff1f;答案是&#xff1a;哪里都冷&#xff01;冬天最痛苦的莫过于走出空调房——刺骨的风直直的从领口处灌进去那叫一个“透心凉&#xff0c;心飞扬”缠了好几圈的大围巾却根本没什么保暖效果每当这时候&#xff0…

【教程】【FLEX】#004 反射机制

总结&#xff1a; 目前用到反射的主要有两个方法 1. getDefinitionByName //根据类名&#xff0c;返回对象&#xff08;反射实例化对象&#xff09; 2. describeType //根据对象&#xff0c;返回XML格式的属性&#xff0c;方法等信息&#xff08;反射得到…

iOS下JS与OC互相调用(五)--UIWebView + WebViewJavascriptBridge

WebViewJavascriptBridge是一个有点年代的JS与OC交互的库&#xff0c;使用该库的著名应用还挺多的&#xff0c;目前这个库有7000star。我去翻看了它的第一版本已经是4年前了&#xff0c;在版本V4.1.4以及之前&#xff0c;该库只有一个类和一个js 的txt文件&#xff0c;所以旧版…

OpenCV代码提取:Windows上通过DShow获取Camera视频

在OpenCV 3.1中获取视频的模块在videoio(video input and output module)中&#xff0c;调用VideoCapture类接口&#xff0c;除了videoio模块外还依赖core、highgui、imgproc、imgcodecs四个模块&#xff0c;而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科技大本营&#xff08;ID&#xff1a;rgznai100&#xff09;【导读】目前&#xff0c;大多数行人重识别&#xff08;ReID&#xff09;方法主要是从收集的单个人图像数…

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视频的实现&#xff0c;即调用VideoCapture类。在OpenCV的VideoCapture类中并没有提供获取Camera设备列表、支持的编解码类型列表及支持的video size列表接口&#xff0c;这里基…

15篇论文全面概览BERT压缩方法

作者 | Mitchell A. Gordon译者 | 孙薇出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;模型压缩可减少受训神经网络的冗余——由于几乎没有BERT或者BERT-Large模型可用于GPU及智能手机上&#xff0c;这一点就非常有用了。另外&#xff0c;内存与推理速度的提高也能节…

iOS下JS与OC互相调用(七)--Cordova 基础

Cordova 简介 在介绍Cordova之前&#xff0c;必须先提一下PhoneGap。PhoneGap 是Nitobi软件公司2008年推出的一个框架&#xff0c;旨在弥补web 和iOS 之间的不足&#xff0c;使得web 和 iPhone SDK 之间的交互更容易。后来又加入了Android SDK 和BlackBerry SDK&#xff0c;再然…

在linux上MySQL的三种安装方式

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

通过libjpeg-turbo实现对jpeg图像的解码

之前在https://blog.csdn.net/fengbingchun/article/details/89715416中介绍过通过libjpeg-turbo接口实现将数据编码或压缩成jpeg数据并通过FILE的fwrite接口将其直接保存成*.jpg图像&#xff0c;当时用的是libjpeg的接口&#xff0c;其实还可以使用turbojpeg api的接口即tjCom…

AI+大数据顶级技术盛会开幕在即,6.6折特惠票限时抢购

2019年12月5-7日&#xff0c;由中国计算机学会主办&#xff0c;CCF 大数据专家委员会承办&#xff0c;CSDN、中科天玑数据科技股份有限公司协办的中国大数据技术大会&#xff08;BDTC 2019&#xff09;将于北京长城饭店隆重举行。届时&#xff0c;超过百位顶尖技术专家将齐聚于…

iOS下JS与OC互相调用(八)--Cordova详解+实战

1.新建工程&#xff0c;添加Cordova 关键类 我这里用Xcode 8 新建了一个工程&#xff0c;叫 JS_OC_Cordova,然后将Cordova关键类添加进工程。 有哪些关键类呢&#xff1f; 这里添加config.xml 、Private 和 Public 两个文件夹里的所有文件。工程目录结构如下&#xff1a; 然后…

iOS多线程编程之NSOperation和NSOperationQueue的使用

使用 NSOperation的方式有两种&#xff0c; 一种是用定义好的两个子类&#xff1a; NSInvocationOperation 和 NSBlockOperation。 另一种是继承NSOperation 如果你也熟悉Java&#xff0c;NSOperation就和java.lang.Runnable接口很相似。和Java的Runnable一样&#xff0c;NSOpe…

Swift - 使用SwiftHTTP通过HTTPS进行网络请求,及证书的使用

&#xff08;本文代码已升级至Swift3&#xff09;一&#xff0c;证书的生成&#xff0c;以及服务器配置参考我前面写的这篇文章&#xff1a;Tomcat服务器配置https双向认证&#xff08;使用keytool生成证书&#xff09;文章详细介绍了HTTPS&#xff0c;SSL/TLS。还有使用key to…

Linux下通过v4l2获取视频设备名、支持的编解码及视频size列表实现

早些时候给出了在Windows下通过dshow获取视频设备信息的实现&#xff0c;包括获取视频设备名、获取每种视频设备支持的编解码格式列表、每种编解码格式支持的video size列表&#xff0c;见&#xff1a;https://blog.csdn.net/fengbingchun/article/details/102806822 下面给出…

12种主流编程语言输出“ Hello World ”,把我给难住了!

作为一名程序员&#xff0c;在初步学习编程想必都绕不开一个最为基础的入门级示例“Hello World”&#xff0c;那么&#xff0c;你真的了解各个语言“Hello World”的正确写法吗&#xff1f;在我们刚开始打开编程世界的时候&#xff0c;往往写的第一个程序都是简单的文本输出&a…

军哥lnmp一键安装包nginx支持pathinfo配置

ssh里执行&#xff1a;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…