Ios开发之 -- js和ios的交互

==WebViewJavascriptBridge的介绍==

#下载:https://github.com/marcuswestin/WebViewJavascriptBridge

#关于WebViewJavascriptBridge的介绍:http://blog.csdn.net/yanghua_kobe/article/details/8209751

==WebViewJavascriptBridge(在与现有的业务代码结合使用中)的小问题==

*demo部分(  ExampleApp.html界面中第50行):

bridge.callHandler(‘testObjcCallback‘, {‘foo‘: ‘bar‘}, function(response) {

由于底层回传是两个参数responseCallback(message.error, message.responseData) ,因此reponse对应的是message.error,此demo中得到的是undefinded;

*源码实现部分(webview加载回调事件webViewDidFinishLoad):

- (void)webViewDidFinishLoad:(UIWebView *)webView {

if (webView != _webView) { return; }

if (![[_webView stringByEvaluatingJavaScriptFromString:@"typeof WebViewJavascriptBridge == ‘object‘"] isEqualToString:@"true"])
{

NSString *filePath = [[NSBundle mainBundle] pathForResource:@"WebViewJavascriptBridge.js" ofType:@"txt"];

NSString *js = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];

[_webView stringByEvaluatingJavaScriptFromString:js];

}

if (self.startupMessageQueue) {

for (id queuedMessage in self.startupMessageQueue) {

[self _dispatchMessage:queuedMessage];

}

self.startupMessageQueue = nil;

}

if (self.webViewDelegate && [self.webViewDelegate respondsToSelector:@selector(webViewDidFinishLoad:)]) {

[self.webViewDelegate webViewDidFinishLoad:webView];

}

}

WebViewJavascriptBridge的使用流程中要将webview的delegate首先设置为自身,这是必须条件,

如果现有的业务代码中需要使用webview的回调事件,则需要在初始化WebViewJavascriptBridge时制定业务代码自身为后续的delegate;

在设定后续delegate之后,会出现问题;

以上代码会造成webViewDidFinishLoad被调用两次:业务代码中设置webview的回调事件,而以上代码中引入.js.txt资源,资源里有对dom的直接修改,也会触发webViewDidFinishLoad回调函数;

由此造成业务代码中的webViewDidFinishLoad会被执行两次,形成错误或者不必要的多次调用;

处理:在js.txt资源引入之前不执行后续的代码处理,即阻止第一次的viewdidload的后续调用,修改后如下:

- (void)webViewDidFinishLoad:(UIWebView *)webView {

if (webView != _webView) { return; }

if (![[_webView stringByEvaluatingJavaScriptFromString:@"typeof WebViewJavascriptBridge == ‘object‘"] isEqualToString:@"true"])
{

NSString *filePath = [[NSBundle mainBundle] pathForResource:@"WebViewJavascriptBridge.js" ofType:@"txt"];

NSString *js = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];

[_webView stringByEvaluatingJavaScriptFromString:js];

}

//2012-12-3 对于源码的变动,在js.txt加载之前,对于业务后续调用,不处理;

else{

if (self.startupMessageQueue) {

for (id queuedMessage in self.startupMessageQueue) {

[self _dispatchMessage:queuedMessage];

}

self.startupMessageQueue = nil;

}

if (self.webViewDelegate && [self.webViewDelegate respondsToSelector:@selector(webViewDidFinishLoad:)]) {

[self.webViewDelegate webViewDidFinishLoad:webView];

}

}

}

*源码部分(初始化函数):nil不能作为NSdictionary的value;

错误:

- (void)callHandler:(NSString *)handlerName {

[self callHandler:handlerName data:nil responseCallback:nil];

}

正确:

- (void)callHandler:(NSString *)handlerName {

[self callHandler:handlerName data:[NSNull null] responseCallback:nil];

}

==WebViewJavascriptBridge的使用==

===js和ios交互的直接代码实现===

*jos对于js的调用:

[self.paperQuestionsShowWebview stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"setQuestionContent(‘%@‘)",qTitle]];

*js对于ios的调用:

在html js代码中改变当前window的href;

window.location.href="selfEvaluate/"+value;

以上事件触发webview的shouldStartLoadWithRequest的回调事件;

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{

NSString *relativePath = request.mainDocumentURL.relativePath;

if ([relativePath hasSuffix:@".html"]) {

return YES;

}

else{

NSRange doingRange = [relativePath rangeOfString:@"/doing/"];

if (doingRange.length>0) {

//获取用户选择的选项

NSString *userNewChoice = [relativePath substringFromIndex:doingRange.location+doingRange.length];

//更新选项内容到服务器端

//判断当前选项跟已经提交到服务器端的时候一致,如果不一致,则提交到服务器端

if (![userNewChoice isEqualToString:self.currentQuestionAnswer]) {

[self.delegate updateQuestionUserChoiceWithPid:self.paperId questionSequence:self.currentQuestionSequence
choice:userNewChoice

remainTime:self.reimainTime sender:self];

//NSLog(@"update");

}

}

else{

.....

}

return NO;

}

}

===js和ios交互的(WebViewJavascriptBridge)代码实现===

*ios端的实现:

引入头文件:

#import "WebViewJavascriptBridge.h";

指定WebViewJavascriptBridge 属性:

@property (strong, nonatomic) WebViewJavascriptBridge *javascriptBridge;

初始化 WebViewJavascriptBridge;

_javascriptBridge = [WebViewJavascriptBridge bridgeForWebView:_paperQuestionsShowWebview webViewDelegate:self handler:nil];

注册函数;

[_javascriptBridge registerHandler:@"setSubjectiveQuestionScore" handler:^(id data, WVJBResponse *response){

//获取用户选择的选项

NSInteger userScoreChoice = [(NSString *)data integerValue];

//更新选项内容到服务器端

//判断当前选项跟已经提交到服务器端的时候一致,如果不一致,则提交到服务器端

//如果选择新的分数,则同步到服务器端

if (userScoreChoice!=self.currentQuestionScore) {

[self.delegate updateQuestionUserChooseScoreWithPid:self.paperId questionSequence:self.currentQuestionSequence
score:userScoreChoice sender:self];

}

}];

调用js代码;

[_javascriptBridge callHandler:@"setRightAnswer" data:qAnswer ];

*js的实现:

必要的事件注册和初始化:

document.addEventListener(‘WebViewJavascriptBridgeReady‘, onBridgeReady, false);

function onBridgeReady(event) {

var bridge = event.bridge;

//调用初始化函数,取消队列,使消息能够得到直接处理;

bridge.init(function(message) {

alert(message);

});

}

注册函数:

function onBridgeReady(event) {

......

bridge.registerHandler(‘setQuestionContent‘,function(content){

var e_content = document.getElementByIdx_x(‘qcontent‘);

e_content.innerHTML= content;

});

}

实现js对ios的调用:

newChoiceElement.onclick = function(){

bridge.callHandler(‘choose‘,this.value);

}

===js和ios交互的(WebViewJavascriptBridge)代码实现中需要注意的问题===

#ios端必须保障框架中ios的实现作为webview的delegate,而业务代码作为后续的delegate处理在初始化中加入;不然消息得不到传递(会加入一个队列,但是不会触发消息传递);

#js端必须实现init函数,不然消息得不到传递(会加入一个队列,但是不会触发消息传递);

#关于参数(ios端):单个的对象可以直接传递(int等基础类型需要转换成对应的对象);多值传递需要组成NSDictionary进行传递;

#关于参数(js端):单个对象直接传递;多值组成json格式字符串{‘aa‘:‘ss‘,‘sdd‘:‘rrr‘};

#js语法以及编辑器对于错误的指示不明显,造成一些字符或标点错误,以及语法不完成的错误很难被发现,是消耗时间比较长的地方,需要通过寻找更加完善的js编辑器解决;

===代码引入WebViewJavascriptBridge实现ios和js交互的好处===

#协议:自己实现,在通讯的部分需要自己构建传递协议,多人实现造成构建的传递协议不同,比较容易混乱,采用统一的底层框架,可以减少这个问题;

#传递对象的字符转义:框架对这块又处理,不用自己再对一些字符进行转移;

#框架封装了js和ios的多次交互,在实现比较复杂的交互时比较有用,这块如果开发人员自己实现,则代码质量难控制,而且有一定的工作量;

document:属性

document.title //设置文档标题等价于HTML的

document.bgColor //设置页面背景色

document.fgColor //设置前景色(文本颜色)

document.linkColor //未点击过的链接颜色

document.alinkColor //激活链接(焦点在此链接上)的颜色

document.vlinkColor //已点击过的链接颜色

document.URL //设置URL属性从而在同一窗口打开另一网页

document.fileCreatedDate //文件建立日期,只读属性

document.fileModifiedDate //文件修改日期,只读属性

document.fileSize //文件大小,只读属性

document.cookie //设置和读出cookie

document.charset //设置字符集 简体中文:gb2312

document:方法

document.write() //动态向页面写入内容

document_createElement_x_x_x(Tag) //创建一个html标签对象

document.getElementByIdx_xx_x_x(ID) //获得指定ID值的对象

document.getElementsByName(Name) //获得指定Name值的对象

document.body.a(oTag)

body:子对象

document.body //指定文档主体的开始和结束等价于

document.body.bgColor //设置或获取对象后面的背景颜色

document.body.link //未点击过的链接颜色

document.body.alink //激活链接(焦点在此链接上)的颜色

document.body.vlink //已点击过的链接颜色

document.body.text //文本色

document.body.innerText //设置…之间的文本

document.body.innerHTML //设置…之间的HTML代码

document.body.topMargin //页面上边距

document.body.leftMargin //页面左边距

document.body.rightMargin //页面右边距

document.body.bottomMargin //页面下边距

document.body.background //背景图片

document.body.a(oTag) //动态生成一个HTML对象

location:子对象

document.location.hash // #号后的部分

document.location.host // 域名+端口号

document.location.hostname // 域名

document.location.href // 完整URL

document.location.pathname // 目录部分

document.location.port // 端口号

document.location.protocol // 网络协议(http:)

document.location.search // ?号后的部分

常用对象事件:

documeny.location.reload() //刷新网页

document.location.reload(URL) //打开新的网页

document.location.assign(URL) //打开新的网页

document.location.replace(URL) //打开新的网页

selection-选区子对象

document.selection

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-05 17:26:16

Ios开发之 -- js和ios的交互的相关文章

《iOS开发全然上手——使用iOS 7和Xcode 5开发移动与平板应用》之Objective-C新手训练营

编写Hello World应用程序通常被觉得,是学习不论什么编程语言的第一步.在这一章,你将创建iOS版的Hello World应用程序作为起步,高速了解Xcode这个开发iOS应用程序的主要工具. 下一步.你将学习Objective-C的基础知识.在此基础之上.将探索类(class)与对象(object)的知识.它们是构建应用程序的主要基石.与此同一时候,你将创建CarValet应用程序,练习一些类的编写.并学习属性(property)的知识.在本章末尾,你将在指导下完毕编程挑战题以探索子类扩

《iOS开发完全上手——使用iOS 7和Xcode 5开发移动与平板应用》之Objective-C新手训练营

编写Hello World应用程序通常被认为,是学习任何编程语言的第一步.在这一章,你将创建iOS版的Hello World应用程序作为起步,快速了解Xcode这个开发iOS应用程序的主要工具. 下一步,你将学习Objective-C的基础知识.在此基础之上,将探索类(class)与对象(object)的知识,它们是构建应用程序的主要基石.与此同时,你将创建CarValet应用程序,练习一些类的编写,并学习属性(property)的知识.在本章末尾,你将在指导下完成编程挑战题以探索子类扩展的知识

IOS开发数据存储篇—IOS中的几种数据存储方式

IOS开发数据存储篇—IOS中的几种数据存储方式 发表于2016/4/5 21:02:09  421人阅读 分类: 数据存储 在项目开发当中,我们经常会对一些数据进行本地缓存处理.离线缓存的数据一般都保存在APP所在的沙盒之中.一般有以下几种: 1.PList(XML属性列表) 在使用plist进行数据存储和读取,只适用于系统自带的一些常用类型才能用,且必须先获取路径相对麻烦 //写入文件 NSString *doc = [NSSearchPathForDirectoriesInDomains(

iOS开发——淫技篇&iOS开发中各种淫技总结(六)

iOS开发中各种淫技总结(六) swift中指针的使用 在 Swift 中,指针都使用一个特殊的类型来表示,那就是 UnsafePointer<T>.遵循了 Cocoa 的一贯不可变原则,UnsafePointer<T> 也是不可变的.当然对应地,它还有一个可变变体,UnsafeMutablePointer<T>.绝大部分时间里,C 中的指针都会被以这两种类型引入到 Swift 中:C 中 const 修饰的指针对应 UnsafePointer (最常见的应该就是 C

iOS开发——淫技篇&amp;iOS开发中各种淫技总结(五)

淫技篇&iOS开发中各种淫技总结(五) ARC的使用: ARC并不能避免所有的内存泄露.使用ARC之后,工程中可能还会有内存泄露,不过引起这些内存泄露的主要原因是:block,retain循环,对CoreFoundation对象(通常是C结构)管理不善,以及真的是代码没写好. reuseIdentifier 在iOS程序开发中一个普遍性的错误就是没有正确的为UITableViewCells.UICollectionViewCells和UITableViewHeaderFooterViews设置r

iOS开发——实用篇&amp;提高iOS开发效率的方法和工具

提高iOS开发效率的方法和工具 介绍 这篇文章主要是介绍一下我在iOS开发中使用到的一些可以提升开发效率的方法和工具. IDE 首先要说的肯定是IDE了,说到IDE,Xcode不能跑,当然你也可能同时在使用AppCode等其他的IDE,在这里我主要介绍Xcode中提升开发效率的方法. 1.善用快捷键 快捷键是开发中必不可少的,当你善于使用快捷键的时候,十指在键盘上飞舞,那画面太美,我不敢想象. 常用快捷键操作 2.常用代码片段 开发中有一些常用的代码,可以放到代码片段中,然后下次你就可以使用快捷

iOS开发——淫技篇&amp;iOS开发中各种淫技总结(四)

iOS开发中各种淫技总结(四) 一:@autoclosure将一段代码块活着一句表达式自动的封装成一个闭包 func logIfTrue(predicate: () -> Bool) { if predicate() { print("True") } } 调用 logIfTrue({return 2 > 1}) 简写:logIfTrue{2 > 1} 在predicate加上@autoclosure调用的时候就可以省略{}直接使用logIfTrue(2>1)

iOS开发——淫技篇&amp;iOS开发中各种淫技总结(二)

iOS开发中各种淫技总结(二) 先来张笔者电脑上面安装的Mac app 一:for .. in 的内部实现(swift): 1 var g = array.generate() 2 while let obj = g.next() { 3 4 5 print(obj) } 6 二:map/Fileter/Reduce map map方法,其获取一个闭包表达式作为其唯一参数. 数组中的每一个元素调用一次该闭包函数,并返回该元素所映射的值(也可以是不同类型的值). 具体的映射方式和返回值类型由闭包来

iOS开发——淫技篇&amp;iOS开发中各种淫技总结(三)

iOS开发中各种淫技总结(三) 一:send和awk解释 sed -n p filenamesed ----------------------------是一个流编辑器(stream editor) awk ‘BEGIN {print “Hellow"}'awk --------是一种用于处理文本的编程语言工具. 二:传值方式总结 KVO底层会动态长生新的类,只能坚挺属性(一个对象的属性能背多个兑现监听,一个对象能监听多个对象的其他属性) kvc/kvo底层是基于runtime 代理,规范,代