In this tutorial, I have covered How to execute JavaScript in iOS / Objective-C. You can execute JavaScript in iOS applications with the help of JavaScriptCore.framework. This framework is supported in iOS7 & OSX 10.9
List of features supported by Javascript.framework
a) Evaluate JavaScript code in Objective-C
b) Access JavaScript Variables in Objective-C
c) Access JavaScript functions and execute them in Objective-C
d) Execute Objective-C code from JavaScript
e) Export Objective-C classes and use them in JavaScript.
To access JavaScript framework, you need to include the header file
#import <JavaScriptCore/JavaScriptCore.h>
List of Main Classes supported by framework:
JSContext : For any javascript operations you need JSContext.
JSContext *context = [[JSContext alloc] init];
JSValue : JSValue holds JavaScript values,variables and functions. List of main methods in JSValue.
// Convert this value to a corresponding Objective-C object, according to the // conversion specified above. - (id)toObject; // Convert this value to a corresponding Objective-C object, if the result is // not of the specified class then nil will be returned. - (id)toObjectOfClass:(Class)expectedClass; // The value is copied to a boolean according to the conversion specified by the // JavaScript language. - (BOOL)toBool; // The value is copied to a number according to the conversion specified by the // JavaScript language. - (double)toDouble; // The value is copied to an integer according to the conversion specified by // the JavaScript language. - (int32_t)toInt32; // The value is copied to an integer according to the conversion specified by // the JavaScript language. - (uint32_t)toUInt32; // If the value is a boolean, a NSNumber value of @YES or @NO will be returned. // For all other types the value will be copied to a number according to the // conversion specified by the JavaScript language. - (NSNumber *)toNumber; // The value is copied to a string according to the conversion specified by the // JavaScript language. - (NSString *)toString; // The value is converted to a number representing a time interval since 1970, // and a new NSDate instance is returned. - (NSDate *)toDate; // If the value is null or undefined then nil is returned. // If the value is not an object then a JavaScript TypeError will be thrown. // The property "length" is read from the object, converted to an unsigned // integer, and an NSArray of this size is allocated. Properties corresponding // to indicies within the array bounds will be copied to the array, with // Objective-C objects converted to equivalent JSValues as specified. - (NSArray *)toArray; // If the value is null or undefined then nil is returned. // If the value is not an object then a JavaScript TypeError will be thrown. // All enumerable properties of the object are copied to the dictionary, with // Objective-C objects converted to equivalent JSValues as specified. - (NSDictionary *)toDictionary;
Accessing Javascript Code in Objective-C
1).Evaluating Javascript Code
NSString * jsCode = @"1+2"; JSContext *context = [[JSContext alloc] init]; JSValue * value = [context evaluateScript:jsCode]; NSLog(@"Output = %d", [value toInt32]);
2).Access Javascript Variables. Variables and functions are accessed from JSContext.
To access varible from Javascript : context[@”x”]
To access function from javascript : context[@”myfun”]
JSContext *context = [[JSContext alloc] init]; NSString * jsCode = @"var x; x=10;"; [context evaluateScript:jsCode]; JSValue * a =context[@"x"]; NSLog(@"x = %d", [a toInt32]);
3).Access Javascript functions and execute them in Objective-C
//function with arguments JSContext *context = [[JSContext alloc] init]; NSString * jsCode = @"function sum(a,b) { return a+b;} "; [context evaluateScript:jsCode]; JSValue * func =context[@"sum"]; NSArray * args = @[[NSNumber numberWithInt:10],[NSNumber numberWithInt:20]]; JSValue * ret =[func callWithArguments:args]; NSLog(@"10+20 = %d", [ret toInt32]); //function without arguments NSString * jsCode2 = @"function getRandom() { return parseInt(Math.floor((Math.random()*100)+1));} "; [context evaluateScript:jsCode2]; JSValue * func2 =context[@"getRandom"]; for(int i=0;i<5;i++) { JSValue * ret2 =[func2 callWithArguments:nil]; NSLog(@"Random Value = %d", [ret2 toInt32]); }
Call Objective-C code from JavaScript
Objective-C code is called from JavaScript in two ways
1.Code Blocks
Objective-C code block can be called from JavaScript.
JSContext *context = [[JSContext alloc] init]; //we are telling that "sum" is function, takes two arguments context[@"sum"] = ^(int arg1,int arg2) { return arg1+arg2; }; NSString * jsCode =@"sum(4,5);"; JSValue * sumVal = [context evaluateScript:jsCode]; NSLog(@"Sum(4,5) = %d", [sumVal toInt32]); //we are telling that "getRandom" is function, does not take any arguments context[@"getRandom"] = ^() { return rand()%100; }; NSString * jsCode2 =@"getRandom();"; for(int i=0;i<5;i++) { JSValue * sumVal2 = [context evaluateScript:jsCode2]; NSLog(@"Random Number = %d", [sumVal2 toInt32]); }
2.Using JSExport Protocol
You can see the comparison between Objective-C Object and it’s equivalent Javascript Object below.
@interface MyObject @property int x; -(int) getX; +(MyObject *) getSqure:(MyObject*)obj; @end //Usage: MyObject * obj = [MyObject new]; [obj getX]; [MyObject getSqure:obj]; | function MyObject() { //member variable this.x=0; //instance method this.getX = function() { return this.x; } } //static method MyObject.getSqure = function(obj) { var newObj = new MyObject(); newObj.x = obj.x * obj.x; return newObj; } //Usage: var obj = new MyObject(); obj.x=10; var sqrObj = MyObject.getSqure(obj); |
To make Javascript interacting with Objective-C Object, We need to have a Protocol which should be inherited
from JSExport. Move all the variables and functions to prototype to access them in JavaScript.
@protocol MyObjectExport @property int x; -(int) getX; +(MyObject *) getSqure:(MyObject*)obj; @end @interface MyObject :NSObject <MyObjectExport> //this method is not accessible in javascript -(void) test; @end; @implementation MyObject @synthesize x; -(int) getX { return self.x; } +(MyObject *) getSqure:(MyObject*)obj; { NSLog(@"Calling getSqure"); MyObject * newObj = [MyObject new]; newObj.x = obj.x * obj.x; return newObj; }
Now MyObject(Objective-C)’s variables and functions are directly accessed from javascript.
JSContext * context = [[JSContext alloc] init]; NSString * jsCode = @"function sqrtOf(obj){ return MyObject.getSqure(obj);}"; //adding Objective-C Class to Javascript. context[@"MyObject"]=[MyObject class]; [context evaluateScript:jsCode]; MyObject * obj =[MyObject new]; obj.x =10; JSValue * func =context[@"sqrtOf"]; JSValue * val = [func callWithArguments:@[obj]]; //we got MyObject from javascript. MyObject *sqrtObj = [val toObject]; NSLog(@"Value =%d, %d", obj.x, [sqrtObj getX]);