跟进hybrid混合项目开发已有一段时间了,一直都想着手总结一下js与OC的交互关系,但又感觉一直都还没有摸透,总感觉还差点什么...
下面总结下最近学到的js与OC之间的交互:
简单来说js与OC交互就是通过一些方法使得js可以调用OC中的方法,亦或者OC可以调用js中的方法,使得两者可以互传参数,进行各自处理;下面介绍各自两种方法:
一、OC调用js方法,OC传参数给js:
1.*- (JSValue *)invokeMethod:(NSString *)method withArguments:(NSArray **)arguments;
这个方法可以让我们可以直接在OC上简单地调用JS上的方法。只是如果定义的方法是全局函数,那么很显然应该在JSContext的glocalObject对象上调用该方法;如果是某JavaScript对象上的方法,就应该用相应的JSValue对象调用。
举个例子,在js上有方法:
function buttonClicke()
{
testobject.TestNOParameter();
}
那么方法“buttonClicke()”则是全局函数;
“TestNOParameter()”则是JavaScript对象上的方法;
//比如:buttonClicke是全局函数,所以用globalObject调用,从OC传递arguments回到web:
[[context globalObject] invokeMethod: buttonClicke withArguments:arguments];
[[context globalObject] invokeMethod:@"CallBack" withArguments:@[@"你好世界",@"a",@"b",@"c"]];
//比如:TestNOParameter是JavaScript对象上的方法,所以用相应的testobject调用,从OC传递arguments回到web:
`?????但这个方法我不知道怎么写,望知道的朋友告知一下////////`
`百度上搜到的全是这段:
JSValue还提供- (JSValue *)invokeMethod:(NSString *)method withArguments:(NSArray *)arguments;
让我们可以直接简单地调用对象上的方法。只是如果定义的方法是全局函数,那么很显然应该在JSContext的globalObject对象上调用该方法;
如果是某JavaScript对象上的方法,就应该用相应的JSValue对象调用.`
但是我比较笨,不知道所谓的"应该用相应的JSValue对象调用"应该怎么写,请教大家;
2.*- (JSValue *)evaluateScript:(NSString **)script;
这个方法可以简单地在OC上调用js的方法脚本;
比如:
//通过oc方法调用js的alert
[context evaluateScript:@"alert('test js OC')";];
再如js中有方法如下:
function buttonClicke()
{
testobject.alert(value);
}
OC中可以这样调用:前面是先“对象.方法=”,后面再是“方法(回传参数)”;
[context evaluateScript:[NSString stringWithFormat:@"testobject.alert = alert('%@');",@"回传"]];
二、js调用OC方法,js传参数给OC:
1.使用block 直接调用
如果js有方法:
function buttonClicke()
{
Tank("参数");
}
则OC中可以直接使用block响应js的这个Tank方法:
context[@"Tank"] = ^() {
NSArray *arguments = [JSContext currentArguments]; //传过来的是一个数组
NSString *string = arguments[0];
};
//拿到参数后就可以干嘛干嘛了
//或者不用传参数,js那边点击了这个方法,OC这边响应进入到block里,想干嘛就在这里干嘛就是了。
或者js有方法
function clicke()
{
alert(value);
}
OC中可以直接执行并返回值给js用:
context[@"alert"] = ^() {
return @"回传参数";
};
2.使用JSExport 对象调用
在OC中凡事添加了JSExport协议的协议,所规定的方法、变量等就会对js开放,就可以通过js调用到;
通过JSExport协议的重载宏,可以告诉js调用什么方法时,会执行OC端的什么方法;
如js方法为:testobject.TestOneParameter('参数1');
//testobject 是 js 对象,TestOneParameter是方法名,后面为参数,方法名可随意起,没有规范,并不像有些博客上写的要与协议方法拼起来的名字一样,没有必要的。
* 首先创建一个类 继承NSObject并遵循 规定好的这个协议,这个协议遵循JSExport协议:
#import
#import
//首先创建一个实现了JSExport协议的协议
@protocol TestJSObjectProtocol
//使用JSExport重载宏JSExportAs来声明方法:
//点进JSExportAs里面看API,可以发现其规则:前面是js的方法如:TestOneParameter;
后面是OC里的这个协议里的方法,(注意后面一定要有一个参数,即使js那边的没有参数,这边也要这样写,大不了接收到的参数为null,这个规则在JSExportAs里写有,note那里);
这一句的意思是告诉js:当执行js端的TestOneParameter方法时(当然,这个方法可以随意其他名字),会调用OC端的“ -(void)TestNOParameter:(id)args);”这个方法,也叫注册
JSExportAs(TestOneParameter, -(void)TestNOParameter:(id)args);
@end
//然后在创建的类遵循上边的协议
@interface EXWebViewBridge : NSObject
@end
* 然后去.m里实现或者在其他遵循这个协议的类里实现
-(void)TestNOParameter:(id)args
{
NSLog(@"this is ios TestNOParameter = %@",args);
}
* 将这个类创建一个新对象赋给JS的对象
js是通过对象调用的,我们假设js里面有一个对象 testobject 在调用方法
context[@"testobject"]=[EXWebViewBridge new];
//这样就可以了,当JS那边在调用一个方法时,
//如:testobject.TestOneParameter('参数1'),就会来到OC里的协议里使用OC的对象代替JS的对象 并调用对应的协议方法去实现,并传参数过来。
三、下面是代码部分
1,index.html文件