转自:http://blog.youkuaiyun.com/woaifen3344/article/details/42742893
Swift版与JS交互实战篇:
OC版与JS交互实战篇:
因为项目需要做一个活动,而这个活动的信息是源于HTML5写的,而这个操作网页的过程上,
是需要到与原生APP这边交互的,因为这就增加了一个需求,那就是与JS交互。
目前很流行的库有WebviewJavaScriptBridge和OVGap,这两个库都是让webview与JS建立起一条桥梁,
这样就可以相互通信了。
花了两天的时间,反反复复地研究了WebviewJavaScriptBridge和OVGap这两个库,也在网上搜索了很多的
相关博客看,可是都没有满足我的需求。网上的教程几乎都是webview给调用JS,使用系统提供的方法,这是
想学Easy就可以做到的,但是如果想让JS调用我们的原生的方法,那就不容易了,就需要一条桥梁,在JS响应的
时候能回调OC的方法。这两个库都是可以满足我们的,但是在JS端需要添加对应的JS,对于前者,还需要把响应的
方法放到桥梁内,如:
- functionconnectWebViewJavascriptBridge(callback){
- if(window.WebViewJavascriptBridge){
- callback(WebViewJavascriptBridge)
- }else{
- document.addEventListener('WebViewJavascriptBridgeReady',function(){
- callback(WebViewJavascriptBridge)
- },false)
- }
- }
- connectWebViewJavascriptBridge(function(bridge){
- varuniqueId=1
- functionlog(message,data){
- varlog=document.getElementById('log')
- varel=document.createElement('div')
- el.className='logLine'
- el.innerHTML=uniqueId+++'.'+message+':<br/>'+JSON.stringify(data)
- if(log.children.length){log.insertBefore(el,log.children[0])}
- else{log.appendChild(el)}
- }
- bridge.init(function(message,responseCallback){
- log('JSgotamessage',message)
- vardata={'JavascriptResponds':'Wee!'}
- log('JSrespondingwith',data)
- responseCallback(data)
- })
- bridge.registerHandler('testJavascriptHandler',function(data,responseCallback){
- log('ObjCcalledtestJavascriptHandlerwith',data)
- varresponseData={'JavascriptSays':'Rightbackatcha!'}
- log('JSrespondingwith',responseData)
- responseCallback(responseData)
- })
- varbutton=document.getElementById('buttons').appendChild(document.createElement('button'))
- button.innerHTML='SendmessagetoObjC'
- button.onclick=function(e){
- e.preventDefault()
- vardata='HellofromJSbutton'
- log('JSsendingmessage',data)
- bridge.send(data,function(responseData){
- log('JSgotresponse',responseData)
- })
- }
- document.body.appendChild(document.createElement('br'))
- varcallbackButton=document.getElementById('buttons').appendChild(document.createElement('button'))
- callbackButton.innerHTML='FiretestObjcCallback'
- callbackButton.onclick=function(e){
- e.preventDefault()
- log('JScallinghandler"testObjcCallback"')
- bridge.callHandler('testObjcCallback',{'foo':'bar'},function(response){
- log('JSgotresponse',response)
- })
- }
- })
- </script>
connectWebViewJavascriptBridge
这个方法是必须的,而响应要放在这个方法中,这样对安卓端可能会中影响,于是放弃了这个库的使用。
将下来是使用OVGap这个库。
使用这个库前,需要给HTML5中引入对方的脚本,叫ovgap.js,可到Github下载:
- ;(function(){
- varrequire,define;
- (function(){
- varmodules={},
- //StackofmoduleIdscurrentlybeingbuilt.
- requireStack=[],
- //MapofmoduleID->indexintorequireStackofmodulescurrentlybeingbuilt.
- inProgressModules={},
- SEPERATOR=".";
- functionbuild(module){
- varfactory=module.factory,
- localRequire=function(id){
- varresultantId=id;
- //Itsarelativepath,solopoffthelastportionandaddtheid(minus"./")
- if(id.charAt(0)==="."){
- resultantId=module.id.slice(0,module.id.lastIndexOf(SEPERATOR))+SEPERATOR+id.slice(2);
- }
- returnrequire(resultantId);
- };
- module.exports={};
- deletemodule.factory;
- factory(localRequire,module.exports,module);
- returnmodule.exports;
- }
- require=function(id){
- if(!modules[id]){
- throw"module"+id+"notfound";
- }elseif(idininProgressModules){
- varcycle=requireStack.slice(inProgressModules[id]).join('->')+'->'+id;
- throw"Cycleinrequiregraph:"+cycle;
- }
- if(modules[id].factory){
- try{
- inProgressModules[id]=requireStack.length;
- requireStack.push(id);
- returnbuild(modules[id]);
- }finally{
- deleteinProgressModules[id];
- requireStack.pop();
- }
- }
- returnmodules[id].exports;
- };
- define=function(id,factory){
- if(modules[id]){
- throw"module"+id+"alreadydefined";
- }
- modules[id]={
- id:id,
- factory:factory
- };
- };
- define.remove=function(id){
- deletemodules[id];
- };
- define.moduleMap=modules;
- })();
- define("ov_gap",function(require,exports,module){
- varovGap={
- callbackId:Math.floor(Math.random()*2000000000),
- callbacks:{},
- commandQueue:[],
- groupId:Math.floor(Math.random()*300),
- groups:{},
- listeners:{},
- invoke:function(cmd,params,onSuccess,onFail){
- if(!cmd)cmd="defaultCommand";
- if(!params)params={};
- this.callbackId++;
- this.callbacks[this.callbackId]={
- success:onSuccess,
- fail:onFail
- };
- varrurl="ovgap://"+cmd+"/"+JSON.stringify(params)+"/"+this.callbackId;
- document.location=rurl;
- },
- dispatchCommand:function(cmd,params,onSuccess,onFail){
- if(!cmd)cmd="defaultCommand";
- if(!params)params={};
- this.callbackId++;
- this.callbacks[this.callbackId]={
- success:onSuccess,
- fail:onFail
- };
- varcommand=cmd+"/"+JSON.stringify(params)+"/"+this.callbackId;
- this.commandQueue.push(command);
- },
- fetchNativeCommands:function(){
- varjson=JSON.stringify(this.commandQueue);
- this.commandQueue=[];
- returnjson;
- },
- activate:function(){
- document.location="ovgap://ready";
- },
- //returngroupID
- createGroup:function(){
- this.groupId++;
- this.groups[this.groupId]=[];
- returnthis.groupId;
- },
- dispatchCommandInGroup:function(cmd,params,onSuccess,onFail,groupId){
- if(!this.groups[groupId])returnfalse;
- if(!cmd)cmd="defaultCommand";
- if(!params)params={};
- this.callbackId++;
- this.callbacks[this.callbackId]={
- success:onSuccess,
- fail:onFail
- };
- varcommand=cmd+"/"+JSON.stringify(params)+"/"+this.callbackId;
- this.groups[groupId].push(command);
- returntrue;
- },
- activateGroup:function(groupId){
- if(!this.groups[groupId])returnfalse;
- document.location="ovgap://group/"+groupId;
- },
- fetchNativeGroupCommands:function(groupId){
- if(!this.groups[groupId])return[];
- varjson=JSON.stringify(this.groups[groupId]);
- this.groups[groupId]=[];
- returnjson;
- },
- callbackSuccess:function(callbackId,params){
- try{
- ovGap.callbackFromNative(callbackId,params,true);
- }catch(e){
- console.log("Errorinerrorcallback:"+callbackId+"="+e);
- }
- },
- callbackError:function(callbackId,params){
- try{
- ovGap.callbackFromNative(callbackId,params,false);
- }catch(e){
- console.log("Errorinerrorcallback:"+callbackId+"="+e);
- }
- },
- callbackFromNative:function(callbackId,params,isSuccess){
- varcallback=this.callbacks[callbackId];
- if(callback){
- if(isSuccess){
- callback.success&&callback.success(callbackId,params);
- }else{
- callback.fail&&callback.fail(callbackId,params);
- }
- deleteovGap.callbacks[callbackId];
- };
- },
- addGapListener:function(listenId,onSuccess,onFail){
- if(!listenId||!onSuccess||!onFail)return;
- this.listeners[listenId]={
- success:onSuccess,
- fail:onFail
- };
- },
- removeListener:function(listenId){
- if(!this.listeners[listenId])return;
- this.listeners[listenId]=null;
- },
- triggerListenerSuccess:function(listenId,params){
- if(!this.listeners[listenId])return;
- varlistener=this.listeners[listenId];
- listener.success&&listener.success(listenId,params);
- },
- triggerListenerFail:function(listenId,params){
- if(!this.listeners[listenId])return;
- varlistener=this.listeners[listenId];
- listener.fail&&listener.fail(listenId,params);
- }
- };
- module.exports=ovGap;
- });
- window.ov_gap=require("ov_gap");
- })();
给按钮添加一个点击事件,回调如下:
- functiononButtonClick(){
- //下面是我需要处理的事,处理完之后
- alert('这里我是要处理一些事的,如果有需要的话。');
- //这里是回调我们前端与后端商量好的方法
- //activityList是oc中的方法
- window.ov_gap.invoke("activityList",null,success,fail);
- }
这样就从JS回调到了IOS端的OC方法,然后处理我们想做的事。
可是这两个库都需要添加这些东西,做HTML5的人可不愿意,因为这样的话,对于iOS的处理是一种,对于安卓和WP呢?又得写一份吗?
于是我又去寻找别的库,有一个叫apache cordova的库,是支持ios,Android,wp的,可是太大了,又是英文的,安装也很困难,学习成本太高,
于是看了看就放弃了,这么大的库,给我们带来的可不一定是好处多于动坏处啊。
转了一圈又回到了原生的,有一个库叫JavaScriptCore,这个是IOS7以后才开放的API,这可以极大的简化了我们的需求,非常的简单,
我们只需要注入一个方法,就可以在JS中调用此方法来跟原生的OC交互。
首先得加入库
- #import<JavaScriptCore/JavaScriptCore.h>
JSContext这个可是关键。
- //webView对象
- @property(nonatomic,strong,readonly)UIWebView*webView;
- @property(nonatomic,strong,readonly)JSContext*jsContext;
下面是在webview加载完成后, 关联JS与OC:
- -(void)webViewDidFinishLoad:(UIWebView*)webView{
- [_activityViewstopAnimating];
- [selfdismiss];
- if(_jsContext==nil){
- //1.
- _jsContext=[webViewvalueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
- //2.关联打印异常
- _jsContext.exceptionHandler=^(JSContext*context,JSValue*exceptionValue){
- context.exception=exceptionValue;
- DDLogVerbose(@"异常信息:%@",exceptionValue);
- };
- _jsContext[@"activityList"]=^(NSDictionary*param){
- DDLogVerbose(@"%@",param);
- };
- //Mozilla/5.0(iPhone;CPUiPhoneOS10_10likeMacOSX)AppleWebKit/600.1.4(KHTML,likeGecko)Mobile/12B411
- iduserAgent=[webViewstringByEvaluatingJavaScriptFromString:@"navigator.userAgent"];
- DDLogVerbose(@"%@",userAgent);
- }
- }
上面
activityList是商定好的方法名称,在JS中写法:
- <inputtype="button"value="测试log"οnclick="activityList({'tytyty':'hehe'})"/>
那么经过这两天的摸索,学习到了很多的知识。
写DEMO的过程中,由于 后台并没有提供好HTML5页面的交互来测试,需要自己写,
我这里是使用apache服务器,在本地创建一个HTML5页面,自己写一些JS来测试的,
如果大家不知道怎么写JS,其实是很简单的,上w3cschool看一看,就明白了,so easy!!!!
之所以要写下这篇文章,是因为我发现在网上搜索出来的文章中,都是相互复制的,看来看去都是
一样的东西而且还都是OC调JS的代码,实在是不快。
写下的点滴,希望对大家有用。
另外,也许我上面所讲的一些关于OVGap和WebviewJavaScriptBridge的知识是有不正确的地方,还请指出来,
你们的反馈,会是对我最大的帮助,谢谢