iOS JavaScriptCore use

JavaScriptCore is a new feature introduced iOS7, JavaScriptCore running kernel can be understood as a browser, using JavaScriptCore can use native code (mainly referring objectiveC and swift) and js code to call each other, to understand this paper from several aspects.

  • native call js code
  • js call native code
  • Exception Handling
  • JavaScriptCore and combined use of webView

To use JavaScriptCore, first of all we need to introduce its first document `#import <JavaScriptCore / JavaScriptCore.h>`

The head which introduces several important objects

#import "JSContext.h"
#import "JSValue.h"
#import "JSManagedValue.h"
#import "JSVirtualMachine.h"
#import "JSExport.h"
  • JavaScript is running JSContext context of his main role is to execute js code and registered native method interfaces
  • JSValue JSContext return the execution result, he may be any type js (basic data types and functions, such as type, object type, etc.), and the method has an object into a native object.
  • JSManagedValue is JSValue package, which can solve the problem with circulating between js and acoustic code references
  • Memory native JS objects JSVirtualMachine management and run-time management of exposure js
  • JSExport is a protocol, which can be done by implementing the object is a native to the storm drain js

native call js code

Look at the following three common situations, executed between js code, documentation or network js code, registered js reusing JSValue call

//直接执行js代码
- (void)evaluateScript {
    //定义一个js并执行函数
    JSValue *exeFunction1 = [self.jsContext evaluateScript:@"function hi(){ return 'hi' }; hi()"];
    //执行一个闭包js
    JSValue *exeFunction2 = [self.jsContext evaluateScript:@"(function(){ return 'hi' })()"];
}

//执行一段js文档中的代码
//更多的应用场景使用网络或者本地文档加载一段js代码,充分利用其灵活性
- (void)evaluateScriptFromJSFile {
    NSString * path = [[NSBundle mainBundle] pathForResource:@"core" ofType:@"js"];
    NSString * html = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
    JSValue *constructor = [self.jsContext evaluateScript:html];
}

//注册js方法,然后在利用JSValue调用
- (void)regiestJSFunction {
    //注册一个函数
    [self.jsContext evaluateScript:@"var hello = function(){ return 'hello' }"];
    //调用
    JSValue *value1 = [self.jsContext evaluateScript:@"hello()"];
    
    //注册一个匿名函数
    JSValue *jsFunction = [self.jsContext evaluateScript:@" (function(){ return 'hello objc' })"];
    //调用
    JSValue *value2 = [jsFunction callWithArguments:nil];
}

Here are a few important caveats.

After return type of the method jsContext performed evaluateScript

For the native, the return type is JSValue, which is the Native execution of the js object unified package types, in fact he corresponding js different types can lead to the use of it is not the same, common types such as the return value type and returns a function.

If the return value type, JSValue also corresponds to a set of API converted can be converted into any JSValue for native objects, for example:

- (NSArray *)toArray;
- (NSDictionary *)toDictionary;
- (NSDate *)toDate;
- (NSString *)toString;
- (NSNumber *)toNumber;
- (uint32_t)toUInt32;
- (id)toObject;
... 还有很多就不一一列举

If the return is a function of the type, which may be used `jsvalue callWithArguments` method js function calls, for example:

   //注册一个匿名函数
    JSValue *jsFunction = [self.jsContext evaluateScript:@" (function() { return 'hello objc' })"];
    //调用
    JSValue *value2 = [jsFunction callWithArguments:nil];

js be fantastic, where js is the main section of the closure of code, mainly depends on the difference between the following two code

(function() { return 'hello objc' })
function() { return 'hello objc' }

The first line is a closure, execution returns a function code, and the second line is defined a function, result of the second row is performed in an anonymous function defines the js, but the results of no return value.

So omitted when performing the following code (), then the value jsFunction will be empty, and many mobile terminal R & D engineers are not familiar with this js code error prone.

   JSValue *jsFunction = [self.jsContext evaluateScript:@" (function() { return 'hello objc' })"];

Of course, if we define a function at run-time, also you can call back, but instead of using callWithArguments methods, and examples are as follows:

 [self.jsContext evaluateScript:@"var hello = function(){ return 'hello' }"];
  JSValue *value1 = [self.jsContext evaluateScript:@"hello()"];

Implementation of the results is value1 or get a stri large column  iOS JavaScriptCore use value ng type: "hello"

js call native code

native interfaces need to register js before calling native code, using JSContext [ "method name"] can register, followed by a closure, the closure can define the function parameters may be used [JSContext currentArguments]a method to obtain all the parameters of the function calls

Look for some examples:

//注册js方法给Native调用
- (void)regiestNativeFunction {
    //注册一个objc方法给js调用
    self.jsContext[@"log"] = ^(NSString *msg){
        NSLog(@"js:msg:%@",msg);
    };
    //另一种方式,利用currentArguments获取参数
    self.jsContext[@"log"] = ^() {
        NSArray *args = [JSContext currentArguments];
        for (id obj in args) { NSLog(@"%@",obj); }
    };
    
    //使用js调用objc
    [self.jsContext evaluateScript:@"log('hello,i am js side')"];
}

block use still need to pay attention to the problem of circular references, so JSContext static methods that can be used in a block in `+ (JSContext *) currentContext` get to context

Beyond the initial, JSContext can also access to more content, such as:

currentCallee
currentThis
currentArguments
globalObject

callee and this is the js object, callee simply means that the called function objects, this is similar to the native self.

Of course, jsContext can not just put the index function, you can put objects and values, for people familiar with the js code would not be surprised, because the js basically not distinguish objects, concept of functions, objects and functions are the same thing.

In addition to exposure jsContext js object using a method other than the standard, you can also be used to convert the protocol JSExprot objc JSValue complex object into an object and exposed to js

Usage JSExport object

1: First Custom agreements inherited from JSExprot, and the definition needs to be exposed to js properties and methods, such as:

@protocol JSPersonProtocol <JSExport>

@property (nonatomic, copy) NSDictionary *data;
- (NSString *)whatYouName;

@end

2: Create a native object and implement the protocol methods, such as:

.h

@interface Person : NSObject<JSPersonProtocol>

@property (nonatomic, copy)NSString *name;
- (NSString *)whatYouName;

@end

.m

#import "Person.h"

@implementation Person

-(NSString *)whatYouName {
    return @"my name is liuyanwei";
}

-(NSString *)name {
    return @"liuyanwei";
}

@end

use

- (void)useJSExprot {
    Person *p = [[Person alloc]init];
    self.jsContext[@"person"] = p;
    JSValue *value = [self.jsContext evaluateScript:@"person.whatYouName()"];
}

Implementation of the results is, value value: my name is liuyanwei

Exception Handling

//注册js错误处理
- (void)jsExceptionHandler {
    self.jsContext.exceptionHandler = ^(JSContext *con, JSValue *exception) {
        NSLog(@"%@", exception);
        con.exception = exception;
    };
}

JavaScriptCore and combined use UIWebView

The above code is based JSContext if a UIWebView declared, you may be used to obtain JSContext UIWebView objects, you can use the Api JavaScriptCore, the method of obtaining JSContext UIWebView is:

 JSContext *context=[webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];

But unfortunately WKWebView I have not found a method to obtain JSContext, if there is to know friends also want to contact me.

JSVirtualMachine

In the creation of jscontext, you can pass a JSVirtualMachine object, if the object is not passed, will create a new JSVirtualMachine object.

JSVirtualMachine There are three main roles:

1: Supports concurrent js, js operations between multiple concurrent VM is 1: Using multiple context JSVirtualMachine initialization, the objects can be shared jsvalue 2: solve the problem of circular references

注意,当我们 export 一个 OC 或 Swift object 到 JS 中时,不能在这个object 中存储对应的 JS values。这种行为会导致一个retain cycle,JSValue objects 持有他们对应的 JSContext 的强引用,JSContext 则持有export到JS的native object的强引用,即 native object(OC or Swift object) —> JSValue —> JSContext —> native object

reference

Download the demo of this article

Thanks for watching, if you help us, please github and follow the Star , published in the paper technology blog of Liu Yanwei , please indicate the source

Guess you like

Origin www.cnblogs.com/liuzhongrong/p/11961107.html