(0006) iOS 开发之JavaScriptCore 实现UIWebView和HTML的交互
阅读说明:本文不讲解JavaScriptCore 基本使用。网上博客比较多,看几篇基本都会使用了。这里只针对使用过程中遇到的一些问题。以便更好的使用JavaScriptCore。
由于开发的项目是电商项目,涉及到很多UIWebView和HTML的交互。对他们的交互可以说比较熟悉了。一路走来走了,遇到了不少坑,为了大家少走弯路!以此记录使用JavaScriptCore过程中遇到的问题。
WebViewJavascriptBridge(放弃)
之前一直用的是WebViewJavascriptBridge,但由于一下几个原因我决定放弃它:
1.由于需要在HTML中添加代码,不能和安卓公用一套代码
2.iOS 10 中(4.0.4版本崩溃),必须升级。一些在服务端的页面无法跟着升级(会造成线上用户不能响应H5)。
3.JavaScriptCore 使用简单。
JavaScriptCore:(本文重点)
1.JavaScriptSore是苹果在iOS7之后提供的一套框架,它让JS与OC的交互更加简单方便。
2.JavaScriptSore是一套完善的框架,它能满足两者交互的各种需要。
3.使用步骤:
a:导入头文件 #import <JavaScriptCore/JavaScriptCore.h>
b:在.m 中声明一个全局(带下划线)的对象:JSContext *_jsContext;
c:在代理方法中创建对象:
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
if (!_jsContext) {
_jsContext = [m_webviewLivingGoodsDetail valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
_jsContext[@"wst"] = self;// 把控制器给html。以便html中直接调用OC中的方法。wst 双方约定。
}
// 调试 Xcode 控制台打印html中的log。
_jsContext[@"console"][@"log"] = ^(id temObj){
NSLog(@"temObj-------:%@",temObj);
};
// 2. 关联打印异常
_jsContext.exceptionHandler = ^(JSContext *context, JSValue *exceptionValue) {
context.exception = exceptionValue;
NSLog(@"异常信息:%@", exceptionValue);
};
// JavaScript->OC
// 所有jsCallApp 事件都在这里注册好。
// 分享。jsCallApp2Share是OC 的方法。方法名双方约定。
__weak typeof(self)weakSelf = self; //
_jsContext[@"window"][@"wst"][@"jsCallApp2Share"] = ^(id data) {
NSLog(@"jsCallApp2Share called: %@", data);
[weakSelf performSelectorOnMainThread:@selector(didCallApp2Share) withObject:nil waitUntilDone:NO];
};
}
html 中调用OC的方法
// 分享方法
function jsCallApp2Share(){
try{
window.wst.jsCallApp2Share();
}catch(error){
console.log(error.message);
}
}
d:OC->JavaScript(这里两个参数)
// 将dictionaryGoodsDetail字典转换为jsonStr
+ (NSString *)transformDictionaryToJsonStr:(NSDictionary *)dic;
{
if ([NSJSONSerialization isValidJSONObject:dic]) {
NSError *parseError = nil;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dic options:0 error:&parseError];
return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
} else {
return nil;
}
}
方法一:需要将dictionaryGoodsDetail字典转换为jsonStr
NSString *jsonStr = [GeneralUtils transformDictionaryToJsonStr:dictionaryGoodsDetail];
方法二:
__strong NSString *temStrWeak = methodString;
dispatch_async(dispatch_get_main_queue(), ^{
[webview stringByEvaluatingJavaScriptFromString:temStrWeak];
});
方法三:此方法直接将请求数据塞给html。(推荐方法三)
JSValue *temfunction = _jsContext[@"appCallJsGetGoodsDetail"];
[temfunction callWithArguments:@[dictionaryGoodsDetail,@"0"]];
+ (NSString *)transformSingleSlashToDoubleSlashWithJsonStr:(NSString *)jsonStr
{
NSString *singleStr = @"\\"; // 单斜杠Str
NSString *doubleStr = [NSString stringWithFormat:@"%@%@",@"\\",@"\\"]; // 双斜杠Str
NSString *resultStr = [jsonStr stringByReplacingOccurrencesOfString:singleStr withString:doubleStr];
return resultStr;
}
// 将“\” 换成“\\”
jsonStr = [GeneralUtils transformSingleSlashToDoubleSlashWithJsonStr:jsonStr];
这样就好了。但是这种做法维护性太差。
问题2:问题一中以字符串传,让html解析,维护性太差。直接传字典才是王道啊。于是就找到了JavaScriptCore的另一个方法:callWithArguments:这个方法可以不用转字符串。直接传字典。
替换后发现了一个问题多次进入这个webview 会崩溃,活着页面卡死。
这样做,html页面偶尔能出来,更多时候会崩溃:
崩溃1.WebCore`WebCore::RenderStyle
崩溃2.- (JSValue *)callWithArguments:(NSArray *)arguments 偶尔崩到这里。
基本都是
一是: exc_bad_access code=1 address=**** 另一个是: exc_breakpoint (code=exc_i386_bpt subcode=0x0) .
根据上面崩溃:总感觉是webview的渲染问题。
根据崩溃2:找到
根据这篇文章:http://stackoverflow.com/questions/28406952/jsvalue-callwithargumentsnsarray-arguments-crashed-in-ios7-0-4/40125008#40125008
解决了崩溃。就是在html中加了延迟执行。终于不会崩溃。心情舒畅了许多!
但是:在html 中的函数中加个延迟函数。
setTimeout(function(){// 执行代码},650);
思考:这个延时安卓端又不需要,多少又修改了html的代码。这是我最不想做的事。
根据崩溃1:
http://www.cnblogs.com/hui314/p/IOS_javascriptcore_notice.html#undefined 感谢这个文章的作者。必要贴一下文章内容。
IOS7--javascriptcore中jscontext使用要注意的一点
在公司一个项目中,用到了highchart做图表显示的组件,这就要用到了javascriptcore,代码就不上了,说说原理。
需求是这样的,通过http请求server csv格式的数据,然后解析,最后传入LOCAL的html 中用highchart显示出来。
由于需要显示loading,progress等,所以就用了IOS提供的原生NSURLConnection,实现 NSURLConnectionDelegate 和 NSURLConnectionDataDelegate .
原先的设计是这样的,在controller view实现 <UIWebViewDelegate> ,在viewDidLoad 中加载本地的html文件(这个就是显示chart的html,里面配置好chart所需要的一切,只等OC传数据进来),在 - webViewDidFinishLoad: 中初始化JSContext并开始连接请求. 在 - connectionDidFinishLoading: 把数据痛过[JSContext[@"value" callWithArguments:] ]传给对用的js method。
这样做,Chart偶尔能出来,更多时候throw exception。exception有两个,一是: exc_bad_access code=1 address=**** 另一个是: exc_breakpoint (code=exc_i386_bpt subcode=0x0) .
开始怀疑是数据的问题,就把网络请求到的数据储存到本地,然后在- webViewDidFinishLoad: 通过JSContext传给js,结果完全没有问题,chart每次显示完美。
通过搜索,在stackoverflow中了解到报错:exc_bad_access code=1 address=**** 的原因是,使用了已经release的object。通过Debug,跟踪到出问题时候是在调用js method的时候。因为项目用的是ARC,而我们的服务器是放在AWS上面的,并且注册的region是Ireland,服务器响应时间一般在2~5s,(比较慢,因为后台需要计算),我想,是不是在等待的这段时间,OC已经把我的JSContext release了,因为我是在 - webViewDidFinishLoad: 中初始化JSContext对象并开始请求数据的,也就是说,JSContext对象至少闲置了2~5s的时间。
开始修改代码,在 viewdidload 中首先开始请求数据,等请求完成后在开始load local html,然后在- webViewDidFinishLoad: 再初始化JSContext,并把数据传过去[JSContext[@"value" callWithArguments:] ] ,run ... 一切没问题。
ARC的确是方便了我们很多,也许我们在享受它带来好处的同时也要警惕它最大的好处。
于是就按照文章说的。
1.在请求接口成功返回渲染的数据后,再去加载html[self loadWebView];
- (void)loadWebView
{
// 载入webview绘制的界面
NSString *resourcePath = [[NSBundle mainBundle] resourcePath];
NSString *filePath = [resourcePath stringByAppendingPathComponent:@"/html/detail.html"];
NSString *htmlstring = [[NSString alloc]initWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
[webView loadHTMLString:htmlstring baseURL:[NSURL fileURLWithPath:filePath]];
}
2.
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
// dictionaryGoodsDetail为接口返回的数据
JSValue *temfunction = _jsContext[@"appCallJsGetGoodsDetail"];
[temfunction callWithArguments:@[dictionaryGoodsDetail,@"0"]];
}
万事大吉了!
好习惯:实现-del loc{}方法。何时释放心里清楚。
到此:对于UIWebView和HTML的交互能做到和安卓公用一套html。JavaScriptCore使用也很简单。更多方法还有待验证。也可以对
JavaScriptCore进行一层封装。
感谢阅读。
(0006) iOS 开发之JavaScriptCore 实现UIWebView和HTML的交互相关推荐
- iOS开发之AVKit框架使用
2019独角兽企业重金招聘Python工程师标准>>> iOS开发之AVKit框架使用 一.引言 在iOS开发框架中,AVKit是一个非常上层,偏应用的框架,它是基于AVFounda ...
- (0045) iOS 开发之MBProgressHUD 源码学习
(0045) iOS 开发之MBProgressHUD 源码学习 第一部分:学习所得和分析线程 1. 学习到了kvo 的使用 和屏幕方向的旋转判断. 2. 如果调起这个 HUD 的方法不是在主线程调 ...
- (0016)iOS 开发之Mac上Navicat Premium 创建远程连接和本地连接
1.下载安装 (百度云盘里面有安装文件和注册机) 链接: https://pan.baidu.com/s/1kVG1k71 密码: mr5g 破解教程看这篇博客:http://blog.csdn.ne ...
- 李洪强iOS开发之RunLoop的原理和核心机制
李洪强iOS开发之RunLoop的原理和核心机制 搞iOS之后一直没有深入研究过RunLoop,非常的惭愧.刚好前一阵子负责性能优化项目,需要利用RunLoop做性能优化和性能检测,趁着这个机会深入研 ...
- IOS开发之MD5加密和钥匙串的使用-oc
IOS开发之MD5加密和钥匙串的使用-oc 源码在我的主页,md5加密是用户登录安全的一个保障.不可逆的,可以暴力破解的. // // ViewController.m // MD5演练 // // ...
- IOS开发之CALayer基本属性和使用
IOS开发之CALayer基本属性和使用 // // ViewController.m // CALayer // // Created by 鲁军 on 2021/2/21. //#import & ...
- ios开发之plist 的文件的读写以及沙盒容器路径打印
ios开发之plist 的文件的读写以及沙盒容器路径打印 核心代码在这里 // // ViewController.m // 21-plist存储和沙盒路径 // // Created by 鲁军 o ...
- IOS开发之JSON文件的读写
IOS开发之JSON文件的读写 // // ViewController.m // 20-JSON的读写 // // Created by 鲁军 on 2021/2/13. //#import &qu ...
- IOS开发之JSON序列化从客户端发送到服务器端
IOS开发之JSON序列化从客户端发送到服务端的准备工作 共有6种情况 需要序列化 请查看源代码. 服务器端接受我们采用的是java的Tomcat服务器.配合 struts 2 controller框 ...
最新文章
- Zookeeper在Kafka中的作用
- P2261-[CQOI2007]余数求和【数论,约数】
- Cordova(PhoneGap) 环境搭建与基础
- 计算机学院嘉年华标题,我院计算机系举办计算机嘉年华系列活动
- 中英文计算机核心期刊目录
- 洛达检测软件AB1562UT_1.4.4新版本下载,适用洛达全系列
- 网上订餐系统开源代码java_基于SSM实现的网上订餐系统【附源码】(毕设)
- Navicat 添加唯一索引
- 详解Linux系统CPU的内部架构和工作原理
- ssh “Missing privilege separation directory: /run/sshd“
- 瞳孔特征值提取,blink frequency,fixation frequency,saccad extent, pupil diameter等
- UITextField类对象左视图leftView无效--iOS开发
- 复习3个月,雅思首考7.0
- 菩提本无树,明镜亦非台,本来无一物,何处惹尘埃
- IOS gif图片播放 swift
- AcWing 第69场周赛
- Codewars实战(一)
- VMware P2V 转换实验
- nc 文件的nan识别
- 服务器default文件夹可以删除吗,C盘用户文件夹里的Default是什么文件夹,有什么用,能删除么?...