阅读说明:本文不讲解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];

             NSString *methodString =           [NSString stringWithFormat:@"appCallJsGetGoodsDetail('%@','%@')",jsonStr,@"0"];
[_jsContext evaluateScript:methodString];

方法二:

__strong NSString *temStrWeak = methodString;

dispatch_async(dispatch_get_main_queue(), ^{

[webview stringByEvaluatingJavaScriptFromString:temStrWeak];

});

方法三:此方法直接将请求数据塞给html。(推荐方法三)

JSValue *temfunction = _jsContext[@"appCallJsGetGoodsDetail"];

[temfunction callWithArguments:@[dictionaryGoodsDetail,@"0"]];

使用已经介绍完了。下面贴几个遇到的问题。
问题1:
使用方法1和2。需要Dictionary转化为String。遇到一种情况是页面加载不出来:
:即返回的json中有换行,转化为String中是“\n”。这个原因造成html无法正常解析。需要把“\”替换为“\\”。然后作为参数传过去。

+ (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的交互相关推荐

  1. iOS开发之AVKit框架使用

    2019独角兽企业重金招聘Python工程师标准>>> iOS开发之AVKit框架使用 一.引言 在iOS开发框架中,AVKit是一个非常上层,偏应用的框架,它是基于AVFounda ...

  2. (0045) iOS 开发之MBProgressHUD 源码学习

    (0045) iOS 开发之MBProgressHUD 源码学习 第一部分:学习所得和分析线程 1.  学习到了kvo 的使用 和屏幕方向的旋转判断. 2. 如果调起这个 HUD 的方法不是在主线程调 ...

  3. (0016)iOS 开发之Mac上Navicat Premium 创建远程连接和本地连接

    1.下载安装 (百度云盘里面有安装文件和注册机) 链接: https://pan.baidu.com/s/1kVG1k71 密码: mr5g 破解教程看这篇博客:http://blog.csdn.ne ...

  4. 李洪强iOS开发之RunLoop的原理和核心机制

    李洪强iOS开发之RunLoop的原理和核心机制 搞iOS之后一直没有深入研究过RunLoop,非常的惭愧.刚好前一阵子负责性能优化项目,需要利用RunLoop做性能优化和性能检测,趁着这个机会深入研 ...

  5. IOS开发之MD5加密和钥匙串的使用-oc

    IOS开发之MD5加密和钥匙串的使用-oc 源码在我的主页,md5加密是用户登录安全的一个保障.不可逆的,可以暴力破解的. // // ViewController.m // MD5演练 // // ...

  6. IOS开发之CALayer基本属性和使用

    IOS开发之CALayer基本属性和使用 // // ViewController.m // CALayer // // Created by 鲁军 on 2021/2/21. //#import & ...

  7. ios开发之plist 的文件的读写以及沙盒容器路径打印

    ios开发之plist 的文件的读写以及沙盒容器路径打印 核心代码在这里 // // ViewController.m // 21-plist存储和沙盒路径 // // Created by 鲁军 o ...

  8. IOS开发之JSON文件的读写

    IOS开发之JSON文件的读写 // // ViewController.m // 20-JSON的读写 // // Created by 鲁军 on 2021/2/13. //#import &qu ...

  9. IOS开发之JSON序列化从客户端发送到服务器端

    IOS开发之JSON序列化从客户端发送到服务端的准备工作 共有6种情况 需要序列化 请查看源代码. 服务器端接受我们采用的是java的Tomcat服务器.配合 struts 2 controller框 ...

最新文章

  1. Zookeeper在Kafka中的作用
  2. P2261-[CQOI2007]余数求和【数论,约数】
  3. Cordova(PhoneGap) 环境搭建与基础
  4. 计算机学院嘉年华标题,我院计算机系举办计算机嘉年华系列活动
  5. 中英文计算机核心期刊目录
  6. 洛达检测软件AB1562UT_1.4.4新版本下载,适用洛达全系列
  7. 网上订餐系统开源代码java_基于SSM实现的网上订餐系统【附源码】(毕设)
  8. Navicat 添加唯一索引
  9. 详解Linux系统CPU的内部架构和工作原理
  10. ssh “Missing privilege separation directory: /run/sshd“
  11. 瞳孔特征值提取,blink frequency,fixation frequency,saccad extent, pupil diameter等
  12. UITextField类对象左视图leftView无效--iOS开发
  13. 复习3个月,雅思首考7.0
  14. 菩提本无树,明镜亦非台,本来无一物,何处惹尘埃
  15. IOS gif图片播放 swift
  16. AcWing 第69场周赛
  17. Codewars实战(一)
  18. VMware P2V 转换实验
  19. nc 文件的nan识别
  20. 服务器default文件夹可以删除吗,C盘用户文件夹里的Default是什么文件夹,有什么用,能删除么?...

热门文章

  1. 谨慎的覆盖clone方法
  2. 【安全牛学习笔记】手动漏洞挖掘(三)
  3. Unity NGUI ScrollView 苹果式滑动
  4. saiku 3.8 二次开发代码整理步骤(20160727更新)
  5. TP 框架没有考虑完善的功能点:1、表达式查询不支持INSTR形式的查询
  6. codewars-013: Ease the StockBroker
  7. 如何使用Apache的ab工具进行网站性能测试
  8. wince 6.0 串口 读取 readfile 超时问题
  9. 安全***需要掌握的东西
  10. redis安装及错误排查