JSCore
简单描述
JSCore是专门用来解释和执行JS代码,可以直接使用OC代码执行一段JS代码
JSPath就是使用了JSCore做到动态执行JS代码
JSContext
表示JS执行上下文,当JS在执行的过程中,都可以通过JSContext来获取执行时的数据,比如某个人对象的值
JSVirtualMachine
JS运行的虚拟机,有独立的堆空间和垃圾回收机制,主要为JS执行提供资源保障
JSValue
JSValue用来JS和OC中的数据转换 他可以是一个JS函数
JSExport
主要用来把OC中的属性和方法导出到JS环境中 方便在JS调用OC
JS和OC直接的类型转换
通过基本的数据类型创建 JSValue
JSValue *intValue = [JSValue valueWithInt32:10 inContext:context];
JSValue *boolValue = [JSValue valueWithBool:YES inContext:context];
创建一个JSValue对象
JSValue *person = [JSValue valueWithNewObjectInContext:context];
[person setObject:@"left" forKeyedSubscript:@"name"];
[person setObject:@25 forKeyedSubscript:@"age"];
NSLog(@"name: %@", person[@"name"]);
NSLog("name: %@",person objectForKeyedSubscript:@"name");
创建一个JSValue结构体
JSValue *rectValue = [JSValue valueWithRect:CGRectMake(0, 0, 100, 100) inContext:context];
[rectValue toRect];
通过JSValue调用某个函数
[context evaluateScript:@"function add(a,b) {return a+b;}"];
JSValue *addValue = [context[@"add"] callWithArguments:@[@2,@3]];
js和OC通信
JSCore的block
JSPatch 就是通过这种⽅方式实现 JS 调⽤用 Native 的
context[@"_OC_catch"] = ^(JSValue *msg,JSValue *stack) {
self._exceptionBlock([NSString stringWithFormat:@"js expection,\nmsg: %@,\nstacj:\n %@",[msg toObject],[stack toObject]]);
};
JSCore的JSExport
JSExport可以导出OC的属性 实例方法 类方法和初始化方法到JS环境,这样就可以通过JS代码直接调用OC 通过JSExport不仅可以导出自定义类的方法,属性.也可以导出已有类的方法,属性.在导出过程中,类的⽅方法名会被转换成 JS 类型命名,第⼆二个参数的第⼀一 个字⺟母会被⼤大写
- (void)addX:(int)x andY:(int)y;
转换为
addXAndY(x, y);
导出⾃自定义类的⽅方法、属性
@class Member;
@class TeachSet;
@protocol JSTeachSetExportProtocol<JSExport>
@property (nonatomic, copy) NSString *name;
+ (TeachSet *)teachSet;
- (void)initWithName:(NSString *)name members:(NSArray<Member *> *)members;
- (NSArray<Member *> *)currentMembers;
JSExportAs(add, -(BOOL)addMember:(Member *)member);
@end
NS_ASSUME_NONNULL_BEGIN
@interface TeachSet : NSObject<JSTeachSetExportProtocol>
@property (nonatomic, copy) NSString *name; </pre>
+ (TeachSet *)teachSet;
- (instancetype)initWithName:(NSString *)name members:(NSArray<Member *> *)members;
- (BOOL)addMember:(Member *)member;
- (NSArray<Member *> *)currentMembers;
+ (BOOL)maxMemberCount;
@end
// 导出 TeachSet 对象
TeachSet *teachSet = [TeachSet teachSet];
self.context[@"_OC_teachSet"] = teachSet;
// 导出 TeachSet 类
self.context[@"_OC_TeachSet"] = [TeachSet class];
// 导出 Member 类,并创建⼀一个 Member 对象添加到 TeachSet 对象中
// 通过构造函数的⽅方式创建 Member 对象
// addMember 被重命名为 add
self.context[@"_OC_Member"] = [Member class];
[self.context evaluateScript:@"var member = new _OC_Member('Lefe_x', 25);_OC_teachSet.add(member);"];
// 通过类⽅方法创建 Member 对象添加到 TeachSet 对象中
[self.context evaluateScript:@"var member = _OC_Member.member();member.name='Lefe_x_1';member.age=26;_OC_teachSet.add( member);"];
// 没导出会报错,_OC_teachSet.maxMemberCount is not a function
[self.context evaluateScript:@"_OC_teachSet.maxMemberCount()"];
// 获取最终 TeachSet 中的成员数
JSValue *membersValue = [self.context evaluateScript:@"_OC_teachSet.currentMembers()"];
/**
membersValue: (
"name: Lefe_x, age: 25",
"name: Lefe_x_1, age: 26"
)*/
NSLog(@"membersValue: %@", [membersValue toArray]);
导出已有类的⽅方法、属性
把已有类的方法,属性导出到JS环境,允许JS调用
创建一个遵守<JSExport>协议的协议
@protocol UILabelExportProtocol<JSExport>
@property (nullable, nonatomic, copy) NSString *text;
@end
// 通过 runtime 给 UILabel 添加协议 UILabelExportProtocol
class_addProtocol([UILabel class], @protocol(UILabelExportProtocol));
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(40, 100, 200, 44)];
label.text = @"知识⼩小集";
label.textColor = [UIColor blackColor];
[self.view addSubview:label];
// 把 label 导出到 JS 环境,在 JS 执⾏行行环境中 label 的名字为 _OC_label,通过这个名 字来调⽤用 label 的 text 属性
self.context[@"_OC_label"] = label;
// 通过 JS 修改 label 的 text 属性,执⾏行行完成后 label 的 text 被修改为 '关注知识⼩小 集公众号'
[self.context evaluateScript:@"_OC_label.text='关注知识⼩小集公众号'"];
OC和JS通信
OC和JS通信 主要有UIWebView WKWebView和JSCore三种通信方式 其实,UIWebView可以看做JSCore的方式
通过JSCore来调用
JSCore是苹果Safari浏览器的JS引擎
创建Context
JSContext *context = [[JSContext alloc]init];
context.name = @"name";
执行JS代码
NSString *addjs = @"function add(a,b) {return a + b;}; add(1,3)";
JSValue *sumValue = [context evaluateScript:addjs];
NSLog(@"%@",@([sumValue toInt32]));
可以通过callWithArguments来调用js中的某个方法
NSString *addjs = @"function add(a,b) {return a + b;}; add(1,3)";
JSValue *sumValue = [context evaluateScript:addjs];
JSValue *resultValue = [context[@"add"] callWithArguments:@[@2,@4]];
NSLog(@"%@",@([resultValue toInt32]));
监听异常
如果执行js代码时 如果有异常会执行这个block
[context setExceptionHandler:^(JSContext *context, JSValue *exception) {
}];
通过UIWebView来调用
通过 UIWebView 来获取 JSContext ,这样直接通过获取到 context 来执⾏行行 JS 代码
JSContext *context = [_webView valueForKeyPath:@"documentView.webView.mainFrame.JSContext"];
通过WKWebView来调用
WKWebView没有提供JSContext的方法 但是提供了执⾏JS 的⽅法 evaluateJS:
[self.webView evaluateJS:@"function add(a, b) {return a + b;};add(1,3)" completionHandler:^(id _Nullable msg, NSError * _Nullable error) {
NSLog(@"evaluateJS add: %@, error: %@", msg, error);
}];
调试
MAC本地搭建Web服务
想让应⽤用访问⽹网⻚页,那么必须启动⼀一个服务 WebServer,Mac 电脑⾃自带了了⼀一个 web 服务器器 Apache
查看服务器器的信息:
➜ WebKit httpd -v
Server version: Apache/2.4.28 (Unix)
Server built: Oct 9 2017 19:54:20
启动服务器
sudo apachectl start
启动成功后,在浏览器器中输⼊入 http://127.0.0.1/ ,即可访问到默认的⽹网⻚页。在⽬目录 /Library/WebServer/Documents 会放⼈人⽹网⻚页中的信息。把 hybird 这个⽹网⻚页信息放到这个⽬目录下
既可以访问。
http://127.0.0.1/hybird/home
调试WebView
通过Safari和手机配合
当运⾏ APP 的时候,iOS 端加载 WebView(WKWebView 或 UIWebView )时可以通过 Mac ⾃自带的 Safari 来调试所显示的页面
我们来模拟加载 Web ⻚页时的场景,⾸首先需要开启本地的 WebServer,mac ⾃自带 Apache 服务器器,我 们只需启动这个服务器器,即可加载⼀一个⽹网⻚页
sudo apachectl start
Apache 开启后,站点的⽬目录在 /Library/WebServer/Documents 下,我们把写好的⽹网⻚页放到这 个⽬目录下,然后直接可以根据 URL 访问对应的⻚页⾯面,⽐比如在浏览器器中输⼊入: http://电脑ip地 址/web/index.html 即可访问 index.html 这个⻚页⾯面
使⽤用 WKWebView 加载 index.html 这个⻚页⾯面,即可调试这个⻚页⾯面,调试前需要做以下两件事:
手机端开启Web 检查器器:设置 -> 通⽤用 -> Safari -> ⾼级 -> Web 检查器
Mac端显示开发菜单:Safari 浏览器默认没有显示“开发”菜单,需要通过:Safari 浏览器 -> 偏好设置 -> ⾼级 -> 勾选在菜单中显示“开发”设置
设置完后,当启动 APP ,加载 WKWebView 后即可看到 index.html 这个⻚页⾯面。这时即可通过断 点进⾏行行调试
网友评论