# JavascriptCore



1、JSCore 是基于 webkit 以 C/C++ 实现的一个 js 包装，让 js 和 Native 交互变得更加简单。

- JScontext 
  JSContext 代表一个 JavaScript 的执行环境的一个实例。所有JavaScript执行都是在上下文内进行。JSContext还用于管理对象的生命周期内 JavaScript 的虚拟机
- JSValue
  JSValue 是用来接收 JSContext 执行后的返回结果。JSValue 可以是 JS 的任意类型（变量、对象、函数...）
- JSManagedValue
  JSManagedValue 是对 JSValue 的封装，可以解决 JS 和 OC 之间循环引用的问题。JSManagedValue 最常用的用法就是安全的从内存堆区里面引用 JSValue 对象.如果 JSValue 存储在内存的堆区的方式是不正确的,很容易造成循环引用,然后导致 JSContext 对象不能正确的释放掉.
- JSExport
  是一个协议，用来将 Native 对象暴露给 JS，这个对象可以指向给自身和别的对象。
- JSVirtualMachine
  管理 JS 对象空间和所需的资源

2、Native 调用 JS

- 加载  JS 代码
      (JSValue *)evaluateScript:(NSString *)script;

- 调用 JS 方法
      JSvalue *callBack = self.context[@"sayHi"];
      [callback callWithArguments:@[@"杭城小刘"]];
   

3、JS 调用 Native

- 通过 Block 实现。然后在 JS 中直接调用方法即可。需要注意的是在 Block 内部不要直接使用外部定义的 JScontext 对象或 JSValue ，应该作为参数传递进来，或者通过 + (JSContext *)currentContext; 来获取。否则会造成循环引用、内存无法被正确回收
      self.context[@"showMessage"] = ^(NSString *message){
              UIAlertController *alertCtr = [UIAlertController alertControllerWithTitle:@"提示" message:message preferredStyle:UIAlertControllerStyleAlert];
              UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:nil];
              [alertCtr addAction:cancel];
              //注意：方法是在子线程中执行的，需要跟新UI的话，需要切入主线程。
              dispatch_async(dispatch_get_main_queue(), ^{
                  [weakSealf presentViewController:alertCtr animated:YES completion:nil];
              });
          };
- 通过 JSExport 协议实现； JS 需要通过 OC 中注入的对象来调方法，那么方法需要在协议中声明，并且在注入的对象中实现；在 webview 加载完成的时候注入实现协议的 Native 对象
      //声明协议
      
      @proptocol JSInject<JSExport>
      - (void)showMessage:(NSString *)message;
      @end
      
      //实现相应的协议
      
      - (void)showMessage:(NSString *)message{
            UIAlertController *alertCtr = [UIAlertController alertControllerWithTitle:@"提示" message:message preferredStyle:UIAlertControllerStyleAlert];
              UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:nil];
              [alertCtr addAction:cancel];
              //注意：方法是在子线程中执行的，需要跟新UI的话，需要切入主线程。
              dispatch_async(dispatch_get_main_queue(), ^{
                  [weakSealf presentViewController:alertCtr animated:YES completion:nil];
              });
      }
      
      //注入
      
      - (void)webViewDidFinishLoad:(UIWebView *)webView
      {
          //从webview上获取相应的JSContext。
          self.context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
      
          //注入JS需要的“OC”对象
          self.context[@"Bridge"] = [JSInject new];
      }
  

举个🌰

JS call Native

    //对外要暴露的 native 对象（其中挂载了一些属性和方法）
    #import <Foundation/Foundation.h>
    #import <JavaScriptCore/JavaScriptCore.h>
    
    @protocol PersonInjectExport<JSExport>
    
    @property (nonatomic, strong) NSString *name;
    
    @property (nonatomic, strong) NSString *hobby;
    
    - (id)sayHi;
    
    @end
    
    
    @interface PersonInject : NSObject<PersonInjectExport>
    
    @property (nonatomic, strong) NSString *name;
    
    @property (nonatomic, strong) NSString *hobby;
    
    - (id)sayHi;
    
    @end
    
    
    // viewcontroller
    
    - (void)webViewDidFinishLoad:(UIWebView *)webView{
        self.jsContext = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
        PersonInject *person = [[PersonInject alloc] init];
        person.name = @"杭城小刘";
        person.hobby = @"Coding、Movie、Music、Table tennis、Fit";
        self.jsContext[@"lbp"] = person;
    }
    
    //JS
    <body>
    
      嗨。大家好我是
      <p id="name">***</p>
    
      <button id="show">那你做个自我介绍吧</button>
    
    </body>
    <script>
      var u = navigator.userAgent
      var isAndroid = u.indexOf('Android') > -1 || u.indexOf('Linux') > -1
      var isiOS = u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/) //ios终端  
    
      document.getElementById("show").onclick = function () {
        if (isiOS) {
          document.getElementById("name").innerHTML = lbp.name;
          setTimeout(() => {
            alert(lbp.sayHi());
          }, 1000);
        }
      }
    </script>



Native call JS

    //Native
    - (void)callJS{
        JSValue *functionName = self.jsContext[@"sum"];
        NSInteger sum = [[functionName callWithArguments:@[@"2",@"18"]] toInt32];;
        
        UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:@"来自JS 的计算" message:[NSString stringWithFormat:@"%zd",sum] preferredStyle:UIAlertControllerStyleAlert];
        UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:nil];
        [alertVC addAction:okAction];
        [self presentViewController:alertVC animated:YES completion:nil];
    }
    
    //JS
    function sum(a ,b){
    	return parseInt(a) + parseInt(b);
    }


