JSCore

作者: 纳兰沫 | 来源:发表于2020-11-04 16:57 被阅读0次

    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 这个⻚页⾯面。这时即可通过断 点进⾏行行调试

    相关文章

      网友评论

          本文标题:JSCore

          本文链接:https://www.haomeiwen.com/subject/kcmivktx.html