iOS与Javascript交互实战

转自:http://blog.youkuaiyun.com/woaifen3344/article/details/42742893

Swift版与JS交互实战篇:

http://mp.weixin.qq.com/s?__biz=MzIzMzA4NjA5Mw==&mid=214070747&idx=1&sn=57b45fa293d0500365d9a0a4ff74a4e1#rd


OC版与JS交互实战篇:

http://mp.weixin.qq.com/s?__biz=MzIzMzA4NjA5Mw==&mid=214063688&idx=1&sn=903258ec2d3ae431b4d9ee55cb59ed89#rd


因为项目需要做一个活动,而这个活动的信息是源于HTML5写的,而这个操作网页的过程上,

是需要到与原生APP这边交互的,因为这就增加了一个需求,那就是与JS交互。

目前很流行的库有WebviewJavaScriptBridge和OVGap,这两个库都是让webview与JS建立起一条桥梁,

这样就可以相互通信了。

花了两天的时间,反反复复地研究了WebviewJavaScriptBridge和OVGap这两个库,也在网上搜索了很多的

相关博客看,可是都没有满足我的需求。网上的教程几乎都是webview给调用JS,使用系统提供的方法,这是

想学Easy就可以做到的,但是如果想让JS调用我们的原生的方法,那就不容易了,就需要一条桥梁,在JS响应的

时候能回调OC的方法。这两个库都是可以满足我们的,但是在JS端需要添加对应的JS,对于前者,还需要把响应的

方法放到桥梁内,如:

  1. functionconnectWebViewJavascriptBridge(callback){
  2. if(window.WebViewJavascriptBridge){
  3. callback(WebViewJavascriptBridge)
  4. }else{
  5. document.addEventListener('WebViewJavascriptBridgeReady',function(){
  6. callback(WebViewJavascriptBridge)
  7. },false)
  8. }
  9. }
  10. connectWebViewJavascriptBridge(function(bridge){
  11. varuniqueId=1
  12. functionlog(message,data){
  13. varlog=document.getElementById('log')
  14. varel=document.createElement('div')
  15. el.className='logLine'
  16. el.innerHTML=uniqueId+++'.'+message+':<br/>'+JSON.stringify(data)
  17. if(log.children.length){log.insertBefore(el,log.children[0])}
  18. else{log.appendChild(el)}
  19. }
  20. bridge.init(function(message,responseCallback){
  21. log('JSgotamessage',message)
  22. vardata={'JavascriptResponds':'Wee!'}
  23. log('JSrespondingwith',data)
  24. responseCallback(data)
  25. })
  26. bridge.registerHandler('testJavascriptHandler',function(data,responseCallback){
  27. log('ObjCcalledtestJavascriptHandlerwith',data)
  28. varresponseData={'JavascriptSays':'Rightbackatcha!'}
  29. log('JSrespondingwith',responseData)
  30. responseCallback(responseData)
  31. })
  32. varbutton=document.getElementById('buttons').appendChild(document.createElement('button'))
  33. button.innerHTML='SendmessagetoObjC'
  34. button.onclick=function(e){
  35. e.preventDefault()
  36. vardata='HellofromJSbutton'
  37. log('JSsendingmessage',data)
  38. bridge.send(data,function(responseData){
  39. log('JSgotresponse',responseData)
  40. })
  41. }
  42. document.body.appendChild(document.createElement('br'))
  43. varcallbackButton=document.getElementById('buttons').appendChild(document.createElement('button'))
  44. callbackButton.innerHTML='FiretestObjcCallback'
  45. callbackButton.onclick=function(e){
  46. e.preventDefault()
  47. log('JScallinghandler"testObjcCallback"')
  48. bridge.callHandler('testObjcCallback',{'foo':'bar'},function(response){
  49. log('JSgotresponse',response)
  50. })
  51. }
  52. })
  53. </script>

connectWebViewJavascriptBridge

这个方法是必须的,而响应要放在这个方法中,这样对安卓端可能会中影响,于是放弃了这个库的使用。


将下来是使用OVGap这个库。

使用这个库前,需要给HTML5中引入对方的脚本,叫ovgap.js,可到Github下载:

[javascript] view plain copy
print ? 在CODE上查看代码片 派生到我的代码片
  1. ;(function(){
  2. varrequire,define;
  3. (function(){
  4. varmodules={},
  5. //StackofmoduleIdscurrentlybeingbuilt.
  6. requireStack=[],
  7. //MapofmoduleID->indexintorequireStackofmodulescurrentlybeingbuilt.
  8. inProgressModules={},
  9. SEPERATOR=".";
  10. functionbuild(module){
  11. varfactory=module.factory,
  12. localRequire=function(id){
  13. varresultantId=id;
  14. //Itsarelativepath,solopoffthelastportionandaddtheid(minus"./")
  15. if(id.charAt(0)==="."){
  16. resultantId=module.id.slice(0,module.id.lastIndexOf(SEPERATOR))+SEPERATOR+id.slice(2);
  17. }
  18. returnrequire(resultantId);
  19. };
  20. module.exports={};
  21. deletemodule.factory;
  22. factory(localRequire,module.exports,module);
  23. returnmodule.exports;
  24. }
  25. require=function(id){
  26. if(!modules[id]){
  27. throw"module"+id+"notfound";
  28. }elseif(idininProgressModules){
  29. varcycle=requireStack.slice(inProgressModules[id]).join('->')+'->'+id;
  30. throw"Cycleinrequiregraph:"+cycle;
  31. }
  32. if(modules[id].factory){
  33. try{
  34. inProgressModules[id]=requireStack.length;
  35. requireStack.push(id);
  36. returnbuild(modules[id]);
  37. }finally{
  38. deleteinProgressModules[id];
  39. requireStack.pop();
  40. }
  41. }
  42. returnmodules[id].exports;
  43. };
  44. define=function(id,factory){
  45. if(modules[id]){
  46. throw"module"+id+"alreadydefined";
  47. }
  48. modules[id]={
  49. id:id,
  50. factory:factory
  51. };
  52. };
  53. define.remove=function(id){
  54. deletemodules[id];
  55. };
  56. define.moduleMap=modules;
  57. })();
  58. define("ov_gap",function(require,exports,module){
  59. varovGap={
  60. callbackId:Math.floor(Math.random()*2000000000),
  61. callbacks:{},
  62. commandQueue:[],
  63. groupId:Math.floor(Math.random()*300),
  64. groups:{},
  65. listeners:{},
  66. invoke:function(cmd,params,onSuccess,onFail){
  67. if(!cmd)cmd="defaultCommand";
  68. if(!params)params={};
  69. this.callbackId++;
  70. this.callbacks[this.callbackId]={
  71. success:onSuccess,
  72. fail:onFail
  73. };
  74. varrurl="ovgap://"+cmd+"/"+JSON.stringify(params)+"/"+this.callbackId;
  75. document.location=rurl;
  76. },
  77. dispatchCommand:function(cmd,params,onSuccess,onFail){
  78. if(!cmd)cmd="defaultCommand";
  79. if(!params)params={};
  80. this.callbackId++;
  81. this.callbacks[this.callbackId]={
  82. success:onSuccess,
  83. fail:onFail
  84. };
  85. varcommand=cmd+"/"+JSON.stringify(params)+"/"+this.callbackId;
  86. this.commandQueue.push(command);
  87. },
  88. fetchNativeCommands:function(){
  89. varjson=JSON.stringify(this.commandQueue);
  90. this.commandQueue=[];
  91. returnjson;
  92. },
  93. activate:function(){
  94. document.location="ovgap://ready";
  95. },
  96. //returngroupID
  97. createGroup:function(){
  98. this.groupId++;
  99. this.groups[this.groupId]=[];
  100. returnthis.groupId;
  101. },
  102. dispatchCommandInGroup:function(cmd,params,onSuccess,onFail,groupId){
  103. if(!this.groups[groupId])returnfalse;
  104. if(!cmd)cmd="defaultCommand";
  105. if(!params)params={};
  106. this.callbackId++;
  107. this.callbacks[this.callbackId]={
  108. success:onSuccess,
  109. fail:onFail
  110. };
  111. varcommand=cmd+"/"+JSON.stringify(params)+"/"+this.callbackId;
  112. this.groups[groupId].push(command);
  113. returntrue;
  114. },
  115. activateGroup:function(groupId){
  116. if(!this.groups[groupId])returnfalse;
  117. document.location="ovgap://group/"+groupId;
  118. },
  119. fetchNativeGroupCommands:function(groupId){
  120. if(!this.groups[groupId])return[];
  121. varjson=JSON.stringify(this.groups[groupId]);
  122. this.groups[groupId]=[];
  123. returnjson;
  124. },
  125. callbackSuccess:function(callbackId,params){
  126. try{
  127. ovGap.callbackFromNative(callbackId,params,true);
  128. }catch(e){
  129. console.log("Errorinerrorcallback:"+callbackId+"="+e);
  130. }
  131. },
  132. callbackError:function(callbackId,params){
  133. try{
  134. ovGap.callbackFromNative(callbackId,params,false);
  135. }catch(e){
  136. console.log("Errorinerrorcallback:"+callbackId+"="+e);
  137. }
  138. },
  139. callbackFromNative:function(callbackId,params,isSuccess){
  140. varcallback=this.callbacks[callbackId];
  141. if(callback){
  142. if(isSuccess){
  143. callback.success&&callback.success(callbackId,params);
  144. }else{
  145. callback.fail&&callback.fail(callbackId,params);
  146. }
  147. deleteovGap.callbacks[callbackId];
  148. };
  149. },
  150. addGapListener:function(listenId,onSuccess,onFail){
  151. if(!listenId||!onSuccess||!onFail)return;
  152. this.listeners[listenId]={
  153. success:onSuccess,
  154. fail:onFail
  155. };
  156. },
  157. removeListener:function(listenId){
  158. if(!this.listeners[listenId])return;
  159. this.listeners[listenId]=null;
  160. },
  161. triggerListenerSuccess:function(listenId,params){
  162. if(!this.listeners[listenId])return;
  163. varlistener=this.listeners[listenId];
  164. listener.success&&listener.success(listenId,params);
  165. },
  166. triggerListenerFail:function(listenId,params){
  167. if(!this.listeners[listenId])return;
  168. varlistener=this.listeners[listenId];
  169. listener.fail&&listener.fail(listenId,params);
  170. }
  171. };
  172. module.exports=ovGap;
  173. });
  174. window.ov_gap=require("ov_gap");
  175. })();

给按钮添加一个点击事件,回调如下:

[javascript] view plain copy
print ? 在CODE上查看代码片 派生到我的代码片
  1. functiononButtonClick(){
  2. //下面是我需要处理的事,处理完之后
  3. alert('这里我是要处理一些事的,如果有需要的话。');
  4. //这里是回调我们前端与后端商量好的方法
  5. //activityList是oc中的方法
  6. window.ov_gap.invoke("activityList",null,success,fail);
  7. }

这样就从JS回调到了IOS端的OC方法,然后处理我们想做的事。




可是这两个库都需要添加这些东西,做HTML5的人可不愿意,因为这样的话,对于iOS的处理是一种,对于安卓和WP呢?又得写一份吗?

于是我又去寻找别的库,有一个叫apache cordova的库,是支持ios,Android,wp的,可是太大了,又是英文的,安装也很困难,学习成本太高,

于是看了看就放弃了,这么大的库,给我们带来的可不一定是好处多于动坏处啊。


转了一圈又回到了原生的,有一个库叫JavaScriptCore,这个是IOS7以后才开放的API,这可以极大的简化了我们的需求,非常的简单,

我们只需要注入一个方法,就可以在JS中调用此方法来跟原生的OC交互。

首先得加入库

[javascript] view plain copy
print ? 在CODE上查看代码片 派生到我的代码片
  1. #import<JavaScriptCore/JavaScriptCore.h>

JSContext这个可是关键。

  1. //webView对象
  2. @property(nonatomic,strong,readonly)UIWebView*webView;
  3. @property(nonatomic,strong,readonly)JSContext*jsContext;

下面是在webview加载完成后, 关联JS与OC:

  1. -(void)webViewDidFinishLoad:(UIWebView*)webView{
  2. [_activityViewstopAnimating];
  3. [selfdismiss];
  4. if(_jsContext==nil){
  5. //1.
  6. _jsContext=[webViewvalueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
  7. //2.关联打印异常
  8. _jsContext.exceptionHandler=^(JSContext*context,JSValue*exceptionValue){
  9. context.exception=exceptionValue;
  10. DDLogVerbose(@"异常信息:%@",exceptionValue);
  11. };
  12. _jsContext[@"activityList"]=^(NSDictionary*param){
  13. DDLogVerbose(@"%@",param);
  14. };
  15. //Mozilla/5.0(iPhone;CPUiPhoneOS10_10likeMacOSX)AppleWebKit/600.1.4(KHTML,likeGecko)Mobile/12B411
  16. iduserAgent=[webViewstringByEvaluatingJavaScriptFromString:@"navigator.userAgent"];
  17. DDLogVerbose(@"%@",userAgent);
  18. }
  19. }

上面

activityList是商定好的方法名称,在JS中写法:

[javascript] view plain copy
print ? 在CODE上查看代码片 派生到我的代码片
  1. <inputtype="button"value="测试log"οnclick="activityList({'tytyty':'hehe'})"/>
在点击的时候,直接回调是可以的。


那么经过这两天的摸索,学习到了很多的知识。

写DEMO的过程中,由于 后台并没有提供好HTML5页面的交互来测试,需要自己写,

我这里是使用apache服务器,在本地创建一个HTML5页面,自己写一些JS来测试的,

如果大家不知道怎么写JS,其实是很简单的,上w3cschool看一看,就明白了,so easy!!!!


之所以要写下这篇文章,是因为我发现在网上搜索出来的文章中,都是相互复制的,看来看去都是

一样的东西而且还都是OC调JS的代码,实在是不快。


写下的点滴,希望对大家有用。

另外,也许我上面所讲的一些关于OVGap和WebviewJavaScriptBridge的知识是有不正确的地方,还请指出来,

你们的反馈,会是对我最大的帮助,谢谢


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值