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

iOS下JS与原生OC互相调用

iOS开发免不了要与UIWebView打交道,然后就要涉及到JS与原生OC交互,今天总结一下JS与原生OC交互的两种方式。

JS调用原生OC篇

方式一

第一种方式是用JS发起一个假的URL请求,然后利用UIWebView的代理方法拦截这次请求,然后再做相应的处理。
我写了一个简单的HTML网页和一个btn点击事件用来与原生OC交互,HTML代码如下:

<html><header><meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script type="text/javascript">function showAlert(message){alert(message);}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 firstClick() {loadURL("firstClick://shareClick?title=分享的标题&content=分享的内容&url=链接地址&imagePath=图片地址");}</script></header><body><h2> 这里是第一种方式 </h2><br/><br/><button type="button" onclick="firstClick()">Click Me!</button></body>
</html>

然后在项目的控制器中实现UIWebView的代理方法:

#pragma mark - UIWebViewDelegate
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{NSURL * url = [request URL];if ([[url scheme] isEqualToString:@"firstclick"]) {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]];}}UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"方式一" message:@"这是OC原生的弹出窗" delegate:self cancelButtonTitle:@"收到" otherButtonTitles:nil];[alertView show];NSLog(@"tempDic:%@",tempDic);return NO;}return YES;
}

注意:1. JS中的firstClick,在拦截到的url scheme全都被转化为小写。
2.html中需要设置编码,否则中文参数可能会出现编码问题。
3.JS用打开一个iFrame的方式替代直接用document.location的方式,以避免多次请求,被替换覆盖的问题。

早期的JS与原生交互的开源库很多都是用得这种方式来实现的,例如:PhoneGap、WebViewJavascriptBridge。关于这种方式调用OC方法,唐巧早期有篇文章有过介绍:
关于UIWebView和PhoneGap的总结

方式二

在iOS 7之后,apple添加了一个新的库JavaScriptCore,用来做JS交互,因此JS与原生OC交互也变得简单了许多。
首先导入JavaScriptCore库, 然后在OC中获取JS的上下文

JSContext *context = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];

再然后定义好JS需要调用的方法,例如JS要调用share方法:
则可以在UIWebView加载url完成后,在其代理方法中添加要调用的share方法:

- (void)webViewDidFinishLoad:(UIWebView *)webView
{JSContext *context = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];//定义好JS要调用的方法, share就是调用的share方法名context[@"share"] = ^() {NSLog(@"+++++++Begin Log+++++++");NSArray *args = [JSContext currentArguments];dispatch_async(dispatch_get_main_queue(), ^{UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"方式二" message:@"这是OC原生的弹出窗" delegate:self cancelButtonTitle:@"收到" otherButtonTitles:nil];[alertView show];});for (JSValue *jsVal in args) {NSLog(@"%@", jsVal.toString);}NSLog(@"-------End Log-------");};
}

注意:
可能最新版本的iOS系统做了改动,现在(iOS9,Xcode 7.3,去年使用Xcode 6 和iOS 8没有线程问题)中测试,block中是在子线程,因此执行UI操作,控制台有警告,需要回到主线程再操作UI。

其中相对应的html部分如下:

<html><header><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><script type="text/javascript">function secondClick() {share('分享的标题','分享的内容','图片地址');}function showAlert(message){alert(message);}</script></header><body><h2> 这里是第二种方式 </h2><br/><br/><button type="button" onclick="secondClick()">Click Me!</button></body>
</html>

JS部分确实要简单的多了。

OC调用JS篇

方式一

NSString *jsStr = [NSString stringWithFormat:@"showAlert('%@')",@"这里是JS中alert弹出的message"];
[_webView stringByEvaluatingJavaScriptFromString:jsStr];

注意:该方法会同步返回一个字符串,因此是一个同步方法,可能会阻塞UI。

方式二

继续使用JavaScriptCore库来做JS交互。

JSContext *context = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
NSString *textJS = @"showAlert('这里是JS中alert弹出的message')";
[context evaluateScript:textJS];

重点:
stringByEvaluatingJavaScriptFromString是一个同步的方法,使用它执行JS方法时,如果JS 方法比较耗的时候,会造成界面卡顿。尤其是js 弹出alert 的时候。
alert 也会阻塞界面,等待用户响应,而stringByEvaluatingJavaScriptFromString又会等待js执行完毕返回。这就造成了死锁。
官方推荐使用WKWebViewevaluateJavaScript:completionHandler:代替这个方法。
其实我们也有另外一种方式,自定义一个延迟执行alert 的方法来防止阻塞,然后我们调用自定义的alert 方法。同理,耗时较长的js 方法也可以放到setTimeout 中。

function asyncAlert(content) {setTimeout(function(){alert(content);},1);
}

相关文章:

马斯克发首款会上火星的电动皮卡:28万起,可防弹,造型相当“赛博朋克”...

整理 | Jane、非主流出品 | AI科技大本营&#xff08;ID&#xff1a;rgznai100&#xff09;【导读】马斯克今日发布酝酿多年、“真爱系列”的第一辆电动皮卡Cybertruck&#xff0c;Cybertruck 是赛博朋克&#xff08;cyberpunk&#xff09;与卡车&#xff08;truck&#xff09;…

让你提升命令行效率的 Bash 快捷键

为什么80%的码农都做不了架构师&#xff1f;>>> 原文&#xff1a;http://linuxtoy.org/archives/bash-shortcuts.html 生活在 Bash shell 中&#xff0c;熟记以下快捷键&#xff0c;将极大的提高你的命令行操作效率。 编辑命令 Ctrl a &#xff1a;移到命令行首Ct…

程序员的自我修养--链接、装载与库笔记:Windows下的动态链接

Windows下的PE的动态链接与Linux下的ELF动态链接相比&#xff0c;有很多类似的地方&#xff0c;但也有很多不同的地方。 1. DLL简介 DLL即动态链接库(Dynamic-Link Library)的缩写&#xff0c;它相当于Linux下的共享对象。Windows系统中大量采用了这种DLL机制&#xff0c;甚至…

iOS下JS与OC互相调用(一)--UIWebView 拦截URL

1.在JS 中做一次URL跳转&#xff0c;然后在OC中拦截跳转。&#xff08;这里分为UIWebView 和 WKWebView两种&#xff0c;去年因为还要兼容iOS 6&#xff0c;所以没办法只能采用UIWebView来做。&#xff09;2.利用WKWebView 的MessageHandler。3.利用系统库JavaScriptCore&#…

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…