一、JavaScriptCore常用的類
JavaScriptCore作用:JavaScriptCore是蘋果原生API淆攻,用來(lái)JS和OC交互的。
JSContext: JS運(yùn)行環(huán)境,用它去執(zhí)行JS代碼蒲牧,并且通過(guò)它去獲取JS里的數(shù)據(jù)
JSValue: 用于接收J(rèn)S中獲取的數(shù)據(jù)類型也榄,可以是任一對(duì)象巡莹,方法。
二甜紫、OC調(diào)用JS
本質(zhì):JS代碼中已經(jīng)定義好變量和方法降宅,通過(guò)OC去獲取,并且調(diào)用
步驟:
1.創(chuàng)建JS運(yùn)行環(huán)境
2.執(zhí)行JS代碼
3.獲取JS數(shù)據(jù)(變量囚霸,方法)
4.使用JS數(shù)據(jù)腰根,方法
2.1 獲取定義在JS中的變量
可以直接通過(guò)OC修改JS中變量的值
#pragma mark - 獲取JS中定義的變量
- (void)getJSVar{
// JS代碼
NSString *jsCode = @"var arr = [1,2,3]";
// 創(chuàng)建JS運(yùn)行環(huán)境
JSContext *ctx = [[JSContext alloc] init];
// 執(zhí)行JS代碼
[ctx evaluateScript:jsCode];
// 因?yàn)樽兞恐苯佣x在JS中,所以可以直接通過(guò)JSContext獲取邮辽,根據(jù)變量名稱獲取唠雕,相當(dāng)于字典的Key
// 只有先執(zhí)行JS代碼贸营,才能獲取變量
JSValue *jsArr = ctx[@"arr"];?
? jsArr[0] = @5;
// 打印結(jié)果:5,2,3
NSLog(@"%@",jsArr);}
2.2 獲取定義在JS中的方法,并且調(diào)用
實(shí)現(xiàn)OC調(diào)用JS方法
#pragma mark - OC調(diào)用JS
// OC調(diào)用JS方法岩睁,并獲取返回結(jié)果
- (void)ocCallJSFunc{
NSString *jsCode =@"function hello(say){"
" return say; "
"}";
// 創(chuàng)建JS運(yùn)行環(huán)境
JSContext *ctx = [[JSContext alloc] init];
// 因?yàn)榉椒ㄖ苯佣x在JS中钞脂,所以可以直接通過(guò)JSContext獲取,根據(jù)方法名稱獲取捕儒,相當(dāng)于字典的Key
// 執(zhí)行JS代碼
[ctx evaluateScript:jsCode];
// 獲取JS方法冰啃,只有先執(zhí)行JS代碼,才能獲取
JSValue *hello = ctx[@"hello"];
// OC調(diào)用JS方法刘莹,獲取方法返回值
JSValue *result = [hello callWithArguments:@[@"你好"]];
// 打印結(jié)果:你好
NSLog(@"%@",result);
}
三阎毅、JS調(diào)用OC中的block
本質(zhì):一開始JS中并沒(méi)有OC的block,所以沒(méi)法直接調(diào)用OC的block点弯,需要把OC的block扇调,在JS中生成方法,然后在通過(guò)JS調(diào)用抢肛。
步驟:
1.創(chuàng)建JS運(yùn)行環(huán)境
2.在JS中生成對(duì)應(yīng)的OC代碼
3.使用JS調(diào)用狼钮,在JS環(huán)境中生成的block方法,就能調(diào)用到OC的block中.
3.1 JS調(diào)用OC中不帶參數(shù)的block
想通過(guò)JS調(diào)用OC中不帶參數(shù)的block
#pragma mark - JS調(diào)用OC中不帶參數(shù)的block
- (void)jsCallOCBlock1WithNoneArguments{
// 創(chuàng)建JS運(yùn)行環(huán)境
JSContext *ctx = [[JSContext alloc] init];
// JS調(diào)用Block方式// 由于JS本身沒(méi)有OC這個(gè)代碼捡絮,需要給JS中賦值熬芜,就會(huì)自動(dòng)生成右邊的代碼.
// 相當(dāng)于在JS中定義一個(gè)叫eat的方法,eat的實(shí)現(xiàn)就是block中的實(shí)現(xiàn)福稳,只要調(diào)用eat,就會(huì)調(diào)用block
ctx[@"eat"] = ^(){NSLog(@"吃東西");?
? };
// JS執(zhí)行代碼涎拉,就會(huì)直接調(diào)用到block中
NSString*jsCode =@"eat()";?
? [ctx evaluateScript:jsCode];}
3.2 JS調(diào)用OC中帶參數(shù)的block
想通過(guò)JS調(diào)用OC中帶參數(shù)的block
- (void)jsCallOCBlockWithArguments{
// 創(chuàng)建JS運(yùn)行環(huán)境
JSContext *ctx = [[JSContext alloc] init];
// 2.調(diào)用帶有參數(shù)的block
// 還是一樣的寫法,會(huì)在JS中生成eat方法的圆,只不過(guò)通過(guò)[JSContext currentArguments]獲取JS執(zhí)行方法時(shí)的參數(shù)
ctx[@"eat"] = ^(){
// 獲取JS調(diào)用參數(shù)
NSArray *arguments = [JSContext currentArguments];
NSLog(@"吃%@",arguments[0]);?
? };
// JS執(zhí)行代碼,調(diào)用eat方法鼓拧,并傳入?yún)?shù)面包
NSString*jsCode =@"eat('面包')";?
? [ctx evaluateScript:jsCode];
}
四、JS調(diào)用OC中的類
本質(zhì):一開始JS中并沒(méi)有OC的類略板,需要先在JS中生成OC的類毁枯,然后在通過(guò)JS調(diào)用。
步驟
1.OC類必須遵守JSExport協(xié)議叮称,只要遵守JSExport協(xié)議种玛,JS才會(huì)生成這個(gè)類
2.但是還不夠,類里面有屬性和方法瓤檐,也要在JS中生成
3.JSExport本身不自帶屬性和方法赂韵,需要自定義一個(gè)協(xié)議,繼承JSExport挠蛉,在自己的協(xié)議中暴露需要在JS中用到的屬性和方法
4.這樣自己的類只要繼承自己的協(xié)議就好祭示,JS就會(huì)自動(dòng)生成類,包括自己協(xié)議中聲明的屬性和方法
4.1 JS調(diào)用OC自定義類
自定義協(xié)議(PersonJSExport)
@protocolPersonJSExport
@property(nonatomic, strong) NSString *name;
-(void)play;
// 調(diào)用多個(gè)參數(shù)的方法谴古,JS函數(shù)命名規(guī)則和OC還不一樣质涛,很可能調(diào)用不到對(duì)應(yīng)的JS生成的函數(shù)稠歉,為了保證生成的JS函數(shù)和OC方法名一致,OC提供了一個(gè)宏JSExportAs汇陆,用來(lái)告訴JS應(yīng)該生成什么樣的函數(shù)對(duì)應(yīng)OC的方法怒炸,這樣就不會(huì)調(diào)錯(cuò)了。
// PropertyName:JS函數(shù)生成的名字
// Selector:OC方法名
// JS就會(huì)自動(dòng)生成playGame這個(gè)方法JSExportAs(playGame,
- (void)playWithGame:(NSString *)gametime:(NSString *)time);
@end
自定義類(Person)
@interfacePerson: NSObject
@property(nonatomic, strong) NSString *name;
-(void)playWithGame:(NSString*)gametime:(NSString*)time;
@end
@implementationPerson
-(void)play{
NSLog(@"%@玩",_name);
}
-(void)playWithGame:(NSString*)gametime:(NSString*)time{
NSLog(@"%@在%@玩%@",_name,time,game);
}
@end
通過(guò)JS調(diào)用OC自定義類
#pragmamark - JS調(diào)用OC自定義類
- (void)jsCallOCCustomClass{
// 創(chuàng)建Person對(duì)象
Person *p = [[Person alloc] init];? ?
p.name = @"zs";? ?
JSContext *ctx = [[JSContext alloc] init];
// 會(huì)在JS中生成Person對(duì)象毡代,并且擁有所有值
// 前提:Person對(duì)象必須遵守JSExport協(xié)議阅羹,
ctx[@"person"] = p;
// 執(zhí)行JS代碼
// 注意:這里的person一定要跟上面聲明的一樣,因?yàn)樯傻膶?duì)象是用person引用// NSString *jsCode = @"person.play()";
NSString *jsCode = @"person.playGame('德州撲克','晚上')";?
? [ctx evaluateScript:jsCode];
}
4.1 JS調(diào)用OC系統(tǒng)類
問(wèn)題:系統(tǒng)自帶的類教寂,想要通過(guò)JS調(diào)用怎么辦捏鱼,我們又沒(méi)辦法修改系統(tǒng)自帶類的文件
和調(diào)用自定義類一樣,也要弄個(gè)自定義協(xié)議繼承JSExport,描述需要暴露哪些屬性(想要把系統(tǒng)類的哪些屬性暴露,就在自己的協(xié)議聲明)
通過(guò)runtime,給類添加協(xié)議
自定義協(xié)議(UILabelJSExport)
@protocolUILabelJSExport
@property(nonatomic, strong) NSString *text;
@end
JS調(diào)用OC系統(tǒng)類
#pragma mark - JS調(diào)用OC系統(tǒng)類
- (void)jsCallOCSystemClass{?
? // 給系統(tǒng)類添加協(xié)議 class_addProtocol([UILabel class],
@protocol(UILabelJSExport));?
? // 創(chuàng)建UILabel?
UILabel *label= [[UILabel alloc] initWithFrame:CGRectMake(50, 50, 100, 100)];
[self.view addSubview:label];
JSContext *ctx = [[JSContext alloc] init];? ?
// 就會(huì)在JS中生成label對(duì)象晚岭,并且用laebl引用
ctx[@"label"] =label;
// 利用JS給label設(shè)置文本內(nèi)容
NSString *jsCode = @"label.text = 'Oh Year'";?
? [ctx evaluateScript:jsCode];
}