Write iOS apps in Javascript! JavaScriptBridge provides the way to write iOS apps with JavaScript. JavaScriptBridge bridges Cocoa touch to JavaScriptCore (JavaScriptCore.framework is introduced in iOS 7).
You get the power of dynamics of scripting language for your apps.
It is still in development, obviously. You're welcomed to contribute if you find the project interesting!
#import <JavaScriptBridge/JavaScriptBridge.h>
...
// Retrieve the prepared context
JSContext *context = [JSBScriptingSupport globalContext];
// Add framework support if needed.
// ('Foundation', 'UIKit', 'QuartzCore' enabled by default.)
[context addScriptingSupport:@"MapKit"];
[context addScriptingSupport:@"MessageUI"];
// Evaluate script
[context evaluateScript:
@"var window = UIWindow.new();"
@"window.frame = UIScreen.mainScreen().bounds;"
@"window.backgroundColor = UIColor.whiteColor();"
@"window.makeKeyAndVisible();"
];
- Retrieve the
JSContext
instance fromJSBScriptingSupport
. The context includes a lot of system classes that has beenJSExports
adopted.
JSContext *context = [JSBScriptingSupport globalContext];
- Add
JSExports
adopted classes each framework if needed. By default,Foundation
,UIKit
,QuartzCore
frameworks are included.
[context addScriptingSupport:@"MapKit"];
[context addScriptingSupport:@"MessageUI"];
- It is ready to use, writing appliction code and evaluate in JavaScript.
[context evaluateScript:
@"var window = UIWindow.new();"
@"window.frame = UIScreen.mainScreen().bounds;"
@"window.backgroundColor = UIColor.whiteColor();"
@"window.makeKeyAndVisible();"
];
- Create new
JSContext
instance instead usingglobalContext
. You can separate JavaScript environments to use multiple contexts.
JSContext *context = [[JSContext alloc] init];
- Add
JSExports
adopted classes each framework if needed.Foundation
,UIKit
andQuartzCore
frameworks MUST be added.
[context addScriptingSupport:@"Foundation"];
[context addScriptingSupport:@"UIKit"];
[context addScriptingSupport:@"QuartzCore"];
[context addScriptingSupport:@"Accounts"];
[context addScriptingSupport:@"Social"];
Class name
Same as Objective-C
Variable declaration
Get rid of Type name
instead use var
UILabel *label;
var label;
Properties
Use dot syntax
UISlider *slider = [[UISlider alloc] initWithFrame:frame];
slider.backgroundColor = [UIColor clearColor];
slider.minimumValue = 0.0;
slider.maximumValue = 100.0;
slider.continuous = YES;
slider.value = 50.0;
var slider = UISlider.alloc().initWithFrame(frame);
slider.backgroundColor = UIColor.clearColor();
slider.minimumValue = 0.0;
slider.maximumValue = 100.0;
slider.continuous = true;
slider.value = 50.0;
Invoking method
Use dot syntax All colons are removed from the selector Any lowercase letter that had followed a colon will be capitalized
UIWindow *window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
var window = UIWindow.alloc().initWithFrame(UIScreen.mainScreen().bounds);
Struct (CGRect, NSRange, etc.)
Use Hashes
UIView *view = [UIView new];
view.frame = CGRectMake(20, 80, 280, 80);
CGFloat x = view.frame.origin.x;
CGFloat width = view.frame.size.width;
var view = UIView.new();
view.frame = {x: 20, y: 80, width: 280, height: 80};
var x = view.frame.x; // => 20
var width = view.frame.width; // => 280
###Hello world on JavaScriptBridge
This is the most simplest way.
@implementation JSBAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
JSContext *context = [JSBScriptingSupport globalContext];
[context evaluateScript:
@"var window = UIWindow.new();"
@"window.frame = UIScreen.mainScreen().bounds;"
@"window.backgroundColor = UIColor.whiteColor();"
@""
@"var navigationController = UINavigationController.new();"
@"var viewController = UIViewController.new();"
@"viewController.navigationItem.title = 'Make UI with JavaScript';"
@""
@"var view = UIView.new();"
@"view.backgroundColor = UIColor.redColor();"
@"view.frame = {x: 20, y: 80, width: 280, height: 80};"
@""
@"var label = UILabel.new();"
@"label.backgroundColor = UIColor.blueColor();"
@"label.textColor = UIColor.whiteColor();"
@"label.text = 'Hello World.';"
@"label.font = UIFont.boldSystemFontOfSize(24);"
@"label.sizeToFit();"
@""
@"var frame = label.frame;"
@"frame.x = 10;"
@"frame.y = 10;"
@"label.frame = frame;"
@""
@"view.addSubview(label);"
@"viewController.view.addSubview(view);"
@""
@"navigationController.viewControllers = [viewController];"
@""
@"window.rootViewController = navigationController;"
@"window.makeKeyAndVisible();"
];
return YES;
}
@end
Of course, the script is able to be loaded from external file.
@implementation JSBAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSBundle *mainBundle = [NSBundle mainBundle];
NSString *path = [mainBundle pathForResource:@"main" ofType:@"js"];
NSString *script = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
JSContext *context = [JSBScriptingSupport globalContext];
[context evaluateScript:script];
return YES;
}
@end
###Writing apps with only JavaScript
See the UICatalog example.
###Define custom classes
You can define custom class in JavaScript. It is needs to interact system provided framework.
JSB.defineClass(declaration, instanceMembers, staticMembers)
function defines Objective-C class in JavaScript.
Pass the class declaration string to first argument.
Second argument is instance method definitions as hash. The hash object inclueds function object, each keys are to be used as method name.
Example
var MainViewController = JSB.defineClass('MainViewController : UITableViewController', {
// Instance Method Definitions
viewDidLoad: function() {
self.navigationItem.title = 'UICatalog';
},
viewWillAppear: function(animated) {
self.tableView.reloadData();
}
}, {
// Class Method Definitions
attemptRotationToDeviceOrientation: function() {
...
}
});
Example
var MainViewController = JSB.defineClass('MainViewController : UITableViewController <UITableviewDataSource, UITableviewDelegate>', // Declaration
// Instance Method Definitions
{
viewDidLoad: function() {
self.navigationItem.title = 'UICatalog';
},
tableViewNumberOfRowsInSection: function(tableView, section) {
return self.menuList.length;
},
tableViewCellForRowAtIndexPath: function(tableView, indexPath) {
var cell = UITableViewCell.alloc().initWithStyleReuseIdentifier(3, 'Cell');
cell.accessoryType = 1;
cell.textLabel.text = self.menuList[indexPath.row]['title'];
cell.detailTextLabel.text = self.menuList[indexPath.row]['explanation'];
return cell;
},
tableViewDidSelectRowAtIndexPath: function(tableView, indexPath) {
var targetViewController = self.menuList[indexPath.row]['viewController'];
self.navigationController.pushViewControllerAnimated(targetViewController, true);
}
},
{
// Class Method Definitions
...
});
###Modules
JavaScriptBridge provides simple module system require/exports
funcitons, like Node.js.
JSB.require(name)
function enables external module, JSB.exports
publishes a module.
See example.
var ButtonsViewController = JSB.require('buttonsViewController');
var ControlsViewController = JSB.require('controlsViewController');
var WebViewController = JSB.require('webViewController');
var MapViewController = JSB.require('mapViewController');
var MainViewController = JSB.defineClass('MainViewController : UITableViewController', {
viewDidLoad: function() {
self.navigationItem.title = 'UICatalog';
...
});
JSB.exports = MainViewController;
###For Debug
JSB.log
function is the same as NSLog
.
JSB.log('view: %@', self.view);
- iOS 7 or later
- JavaScriptCore.framework
JavaScriptBridge is available through CocoaPods, to install it simply add the following line to your Podfile:
pod "JavaScriptBridge"
kishikawa katsumi, [email protected]
JavaScriptBridge is available under the MIT license. See the LICENSE file for more info.