Some day everybody loses their minds. I have lost mine last weekend…
Or not? I have decided that I will run one of my npm modules on my iPhone.
Is it possible? The short answer is yes, for the longer answer you should read this article. 😉
Background
Apple has introduced a native Objective-C API for JavaScriptCore in iOS 7 and you can use it in your iOS 8 Swift projects too. One can have multiple JavaScript virtual machines and contexts too.
What does it mean in practice?
You can evaluate any kind of JS code in your iOS application, call your methods, pass arguments and use the built-in JavaScript objects and methods like JSON.parse
.
We have this super cool Node.jsNode.js is an asynchronous event-driven JavaScript runtime and is the most effective when building scalable network applications. Node.js is free of locks, so there's no chance to dead-lock any process. thing with the module system and we can transform our Node code with Browserify or WebPack to make it runnable in the browser. And this means that we can run this transformed code in our iOS application with the built-in JavaScriptCore of iOS. We have to do only one trick, assign this
to window
, because we do not have window
in the core.
The how
1. Browserify
After you wrote your JavaScript code and exported your methods and variables with global.myMethod = function () {}
, you should transform it with Browserify.
For this install Browserify with npmnpm is a software registry that serves over 1.3 million packages. npm is used by open source developers from all around the world to share and borrow code, as well as many businesses. There are three components to npm: the website the Command Line Interface (CLI) the registry Use the website to discover and download packages, create user profiles, and... and browserify your code:
npm install -g browserify
browserify main.js -o bundle.js
2. The iOS side
We need a JavaScript environment to run our code, which can be done in the following way:
Do not forget to create a window
variable and assign this
to it, Browserify needs this.
// load the javascript file as a String
let path = NSBundle.mainBundle().pathForResource("bundle", ofType: "js")
var jsSource: String! = String.stringWithContentsOfFile(path!)
// Make browserify work
jsSource = "var window = this; \(jsSource)"
// create a javascript context environment and evaluate the script
var context = JSContext()
context.evaluateScript(jsSource)
The JavaScript object and the stringified JSON representation:
The parsed JSON as a Swift dictionary output:
3. Calling Javascript methods
You can get a reference for JavaScript objects with the objectForKeyedSubscript()
and call your methods with the callWithArguments([])
with any piece of arguments.
// JSON parsing
let calculate = context.objectForKeyedSubscript("calculate")
let JSON = context.objectForKeyedSubscript("JSON")
let JSONparse = JSON.objectForKeyedSubscript("parse")
let JSONString = "{\"foo\":\"bar\",\"bar\":[1,2],\"world\":{\"hello\":4,\"foo\":\"bar\"}}"
let parsed = JSONparse.callWithArguments([JSONString])
let parsedDic = parsed.toDictionary()
Ok, what now?
Can this be a next step in the world of isomorphic JavaScript? Does anybody use it in production to share model, validation or any other business logic between the server and the client?
… and yes my liquid-pid npm module works perfectly in this way 😉
You can find the sample the code here.
The liquid-pid PWM’s output for temperature change visualized with swift-linechart:
Recommended reading