# JavascriptCore 1. JSCore is a JavaScript wrapper implemented in C/C++ based on WebKit that makes interaction between JavaScript and native code simpler. - JSContext JSContext represents an instance of a JavaScript execution environment. All JavaScript execution occurs inside a context. JSContext is also used to manage the lifecycle of JavaScript objects in the VM. - JSValue JSValue is used to receive the return results from JSContext execution. A JSValue can be any JavaScript type (primitive, object, function, etc.). - JSManagedValue JSManagedValue is a wrapper around JSValue that helps resolve retain-cycle issues between JS and Objective-C. The most common use is to safely reference a JSValue stored on the heap. If a JSValue is stored on the heap incorrectly, it can easily create retain cycles that prevent JSContext from being released properly. - JSExport A protocol used to expose native objects to JS; the exposed object can point to itself and to other objects. - JSVirtualMachine Manages the JS object space and needed resources. 2. Native calling JS - Load JS code (JSValue *)evaluateScript:(NSString *)script; - Call JS function JSValue *callback = self.context[@"sayHi"]; [callback callWithArguments:@[@"Hangzhou Xiao Liu"]]; 3. JS calling Native - Implement via a block. Then call the method directly from JS. Note: inside the block do not directly use externally defined JSContext or JSValue; pass them as parameters or obtain them via + (JSContext *)currentContext; otherwise it may cause retain cycles and memory won't be freed correctly. self.context[@"showMessage"] = ^(NSString *message){ UIAlertController *alertCtr = [UIAlertController alertControllerWithTitle:@"Notice" message:message preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:nil]; [alertCtr addAction:cancel]; // Note: the block executes on a background thread; update UI on main thread. dispatch_async(dispatch_get_main_queue(), ^{ [weakSelf presentViewController:alertCtr animated:YES completion:nil]; }); }; - Implement via the JSExport protocol; JS will call methods on an injected Objective-C object, so the methods must be declared in the protocol and implemented on the injected object. Inject the native object when the web view finishes loading. // Protocol declaration @protocol JSInject - (void)showMessage:(NSString *)message; @end // Implementation - (void)showMessage:(NSString *)message{ UIAlertController *alertCtr = [UIAlertController alertControllerWithTitle:@"Notice" message:message preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:nil]; [alertCtr addAction:cancel]; // Note: the method runs on a background thread; update UI on main thread. dispatch_async(dispatch_get_main_queue(), ^{ [weakSelf presentViewController:alertCtr animated:YES completion:nil]; }); } // Injection - (void)webViewDidFinishLoad:(UIWebView *)webView { // Get the JSContext from the web view. self.context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]; // Inject the Objective-C object needed by JS self.context[@"Bridge"] = [JSInject new]; } Example JS calls Native // Native object to expose (with some properties and methods) #import #import @protocol PersonInjectExport @property (nonatomic, strong) NSString *name; @property (nonatomic, strong) NSString *hobby; - (id)sayHi; @end @interface PersonInject : NSObject @property (nonatomic, strong) NSString *name; @property (nonatomic, strong) NSString *hobby; - (id)sayHi; @end // view controller - (void)webViewDidFinishLoad:(UIWebView *)webView{ self.jsContext = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]; PersonInject *person = [[PersonInject alloc] init]; person.name = @"Hangzhou Xiao Liu"; person.hobby = @"Coding, Movie, Music, Table tennis, Fit"; self.jsContext[@"lbp"] = person; } // JS Hi. Hello everyone, I am

***

Native calls JS // Native - (void)callJS{ JSValue *functionName = self.jsContext[@"sum"]; NSInteger sum = [[functionName callWithArguments:@[@"2",@"18"]] toInt32]; UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:@"Calculation from 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); }