一、JavaScriptCore常用的類
JavaScriptCore作用:JavaScriptCore是蘋果原生API,用來JS和OC交互的。
JSContext: JS運行環境,用它去執行JS代碼,并且通過它去獲取JS里的數據
JSValue: 用于接收JS中獲取的數據類型,可以是任一對象,方法。
二、OC調用JS
本質:JS代碼中已經定義好變量和方法,通過OC去獲取,并且調用
步驟:
1.創建JS運行環境
2.執行JS代碼
3.獲取JS數據(變量,方法)
4.使用JS數據,方法
2.1 獲取定義在JS中的變量
可以直接通過OC修改JS中變量的值
#pragma mark - 獲取JS中定義的變量
- (void)getJSVar{
// JS代碼
NSString *jsCode = @"var arr = [1,2,3]";
// 創建JS運行環境
JSContext *ctx = [[JSContext alloc] init];
// 執行JS代碼
[ctx evaluateScript:jsCode];
// 因為變量直接定義在JS中,所以可以直接通過JSContext獲取,根據變量名稱獲取,相當于字典的Key
// 只有先執行JS代碼,才能獲取變量
JSValue *jsArr = ctx[@"arr"];?
? jsArr[0] = @5;
// 打印結果:5,2,3
NSLog(@"%@",jsArr);}
2.2 獲取定義在JS中的方法,并且調用
實現OC調用JS方法
#pragma mark - OC調用JS
// OC調用JS方法,并獲取返回結果
- (void)ocCallJSFunc{
NSString *jsCode =@"function hello(say){"
" return say; "
"}";
// 創建JS運行環境
JSContext *ctx = [[JSContext alloc] init];
// 因為方法直接定義在JS中,所以可以直接通過JSContext獲取,根據方法名稱獲取,相當于字典的Key
// 執行JS代碼
[ctx evaluateScript:jsCode];
// 獲取JS方法,只有先執行JS代碼,才能獲取
JSValue *hello = ctx[@"hello"];
// OC調用JS方法,獲取方法返回值
JSValue *result = [hello callWithArguments:@[@"你好"]];
// 打印結果:你好
NSLog(@"%@",result);
}
三、JS調用OC中的block
本質:一開始JS中并沒有OC的block,所以沒法直接調用OC的block,需要把OC的block,在JS中生成方法,然后在通過JS調用。
步驟:
1.創建JS運行環境
2.在JS中生成對應的OC代碼
3.使用JS調用,在JS環境中生成的block方法,就能調用到OC的block中.
3.1 JS調用OC中不帶參數的block
想通過JS調用OC中不帶參數的block
#pragma mark - JS調用OC中不帶參數的block
- (void)jsCallOCBlock1WithNoneArguments{
// 創建JS運行環境
JSContext *ctx = [[JSContext alloc] init];
// JS調用Block方式// 由于JS本身沒有OC這個代碼,需要給JS中賦值,就會自動生成右邊的代碼.
// 相當于在JS中定義一個叫eat的方法,eat的實現就是block中的實現,只要調用eat,就會調用block
ctx[@"eat"] = ^(){NSLog(@"吃東西");?
? };
// JS執行代碼,就會直接調用到block中
NSString*jsCode =@"eat()";?
? [ctx evaluateScript:jsCode];}
3.2 JS調用OC中帶參數的block
想通過JS調用OC中帶參數的block
- (void)jsCallOCBlockWithArguments{
// 創建JS運行環境
JSContext *ctx = [[JSContext alloc] init];
// 2.調用帶有參數的block
// 還是一樣的寫法,會在JS中生成eat方法,只不過通過[JSContext currentArguments]獲取JS執行方法時的參數
ctx[@"eat"] = ^(){
// 獲取JS調用參數
NSArray *arguments = [JSContext currentArguments];
NSLog(@"吃%@",arguments[0]);?
? };
// JS執行代碼,調用eat方法,并傳入參數面包
NSString*jsCode =@"eat('面包')";?
? [ctx evaluateScript:jsCode];
}
四、JS調用OC中的類
本質:一開始JS中并沒有OC的類,需要先在JS中生成OC的類,然后在通過JS調用。
步驟
1.OC類必須遵守JSExport協議,只要遵守JSExport協議,JS才會生成這個類
2.但是還不夠,類里面有屬性和方法,也要在JS中生成
3.JSExport本身不自帶屬性和方法,需要自定義一個協議,繼承JSExport,在自己的協議中暴露需要在JS中用到的屬性和方法
4.這樣自己的類只要繼承自己的協議就好,JS就會自動生成類,包括自己協議中聲明的屬性和方法
4.1 JS調用OC自定義類
自定義協議(PersonJSExport)
@protocolPersonJSExport
@property(nonatomic, strong) NSString *name;
-(void)play;
// 調用多個參數的方法,JS函數命名規則和OC還不一樣,很可能調用不到對應的JS生成的函數,為了保證生成的JS函數和OC方法名一致,OC提供了一個宏JSExportAs,用來告訴JS應該生成什么樣的函數對應OC的方法,這樣就不會調錯了。
// PropertyName:JS函數生成的名字
// Selector:OC方法名
// JS就會自動生成playGame這個方法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
通過JS調用OC自定義類
#pragmamark - JS調用OC自定義類
- (void)jsCallOCCustomClass{
// 創建Person對象
Person *p = [[Person alloc] init];? ?
p.name = @"zs";? ?
JSContext *ctx = [[JSContext alloc] init];
// 會在JS中生成Person對象,并且擁有所有值
// 前提:Person對象必須遵守JSExport協議,
ctx[@"person"] = p;
// 執行JS代碼
// 注意:這里的person一定要跟上面聲明的一樣,因為生成的對象是用person引用// NSString *jsCode = @"person.play()";
NSString *jsCode = @"person.playGame('德州撲克','晚上')";?
? [ctx evaluateScript:jsCode];
}
4.1 JS調用OC系統類
問題:系統自帶的類,想要通過JS調用怎么辦,我們又沒辦法修改系統自帶類的文件
和調用自定義類一樣,也要弄個自定義協議繼承JSExport,描述需要暴露哪些屬性(想要把系統類的哪些屬性暴露,就在自己的協議聲明)
通過runtime,給類添加協議
自定義協議(UILabelJSExport)
@protocolUILabelJSExport
@property(nonatomic, strong) NSString *text;
@end
JS調用OC系統類
#pragma mark - JS調用OC系統類
- (void)jsCallOCSystemClass{?
? // 給系統類添加協議 class_addProtocol([UILabel class],
@protocol(UILabelJSExport));?
? // 創建UILabel?
UILabel *label= [[UILabel alloc] initWithFrame:CGRectMake(50, 50, 100, 100)];
[self.view addSubview:label];
JSContext *ctx = [[JSContext alloc] init];? ?
// 就會在JS中生成label對象,并且用laebl引用
ctx[@"label"] =label;
// 利用JS給label設置文本內容
NSString *jsCode = @"label.text = 'Oh Year'";?
? [ctx evaluateScript:jsCode];
}