A Meteor / Cordova livecoding experiment for Meteor London
The Meteor History.md file is awash with gems. New features bubble into existence like real-time quantum soup, and this file provides a terse run down of all the latest goodies as they appear:
https://github.com/meteor/meteor/blob/devel/History.md
A perusal shows that with the 0.9.2 release a collection of new command line incantations are available to turn your web apps into fully-fledged, handset-bothering, android & iOS native apps, via the magic of Cordova.
Following the link to the Meteor / Cordova integration wiki page we find a pretty thorough getting started guide, so let's try it out.
Let's build an app. Something simple, but real-time and doing something that's only possible for native apps, beyond the reach of current web-apis.
How about a curious trust experiment in remote vibration?
I can't make a web browser vibrate just yet, but phones seem to do it all the time. How about a button that anyone in the world can press that'll make my phone vibrate? Let's build a button that no one should ever press.
Command lines at the ready? Then let's begin:
Scaffold out a new meteor app:
meteor create buzz
Add android support:
meteor add-platform android
Wowzers. That downloads half the internet, but it's the half that makes native app development possible, and meteor configures it all for you, so it's a good thing. There's also the butt ugly download logging and license agreement, but I reckon that'll get better. It gets the job done and its an order of magnitude easier than setting it all up yourself.
Update the app code to include a global collection called Buzz
that will store
a record of each button press.
Buzz = new Mongo.Collection('buzz')
Template.hello.events({
'click button': function () {
Session.set("counter", Session.get("counter") + 1);
// Record the time the button was pressed
Buzz.insert({ createdAt: Date.now() })
}
});
Now we can observe
that collection and whenever a new buzz record is added
it should make my phone vibrate...
if (Meteor.isCordova) {
Meteor.startup(function () {
Buzz.find({}).observe({
added: function (doc) {
// How to do a vibrate?
}
})
})
}
So as a web developer, vibrating a handset is an alien concept to me. It's not a case of using css animation to float the div left and right as fast as you can re-paint all the things; I've got no frame of reference here.
DONT PANIC
That's what Cordova is for. It translates all those weird device specific apis into something familiar and javascripty. While we wait for Mozilla's sterling work in the field of creating web-apis for all the things we have to live with the beautiful transitional stop gap of Cordova plugins. So the process of adding native features to your web app is:
- Go to: http://plugins.cordova.io
- Find a Cordova plugin that does what you want.
- There is no step 3.
Searching for vibration
on the Cordova plugin registry, we find:
org.apache.cordova.vibration
This plugin provides a way to vibrate the device.
http://plugins.cordova.io/#/package/org.apache.cordova.vibration
Boom! That's what we want.
Step 3 was a lie. We still need to instruct meteor to make this new plugin
available in our app, but that's a simple case of prefixing the
plugin id with cordova:
and doing the usual:
meteor add cordova:org.apache.cordova.vibration@0.3.10
Now we can go finish the app!
if (Meteor.isCordova) { // if we're running as a native mobile app...
Meteor.startup(function () {
Buzz.find({}).observe({
added: function (doc) { // ...whenever a buzz is added
// ..do a vibrate
navigator.notification.vibrate(500)
}
})
})
}
Referring back to the docs for the vibration plugin we can see that
navigator.notification.vibrate(500)
tells a handset to vibrate for 500ms. It's
worth noting that the docs also point out that there are iOS quirks, so the usual
web-dev caveats still apply here.
More interestingly, that's it! Our app is now perfect. We have a button, and whenever anyone presses it, it'll cause the mobile app to do a vibrate.
Now we just need to deploy this tele-wobbling MVP.
First up let's push it up to meteor, as it's a nice'n'simple solution for getting your idea onto the internets fast:
meteor deploy buzz
...and we're done, our app is now deployed at http://buzz.meteor.com/ If you try this yourself you likely to run into 2 issues,
- You need to signup for a meteor developer account before you can deploy. It's free and painless, so go for it.
- I already claimed
buzz.meteor.com
so you'll need to choose a different subdomain.
Back to the task at hand, let's finish this. Stop all this talk, I want a native mobile app on my phone, right now:
Enable developer mode on your android device, plug in a usb cable and run:
meteor run android-device --mobile-port buzz.meteor.com:80
It takes a little while to run, but it'll bundle up the front end of your meteor app, grab the Cordova plugins, install it on your device and fire it up.
Providing the --mobile-port buzz.meteor.com:80
argument tells meteor that I
want this mobile app to point to the server running on http://buzz.meteor.com
And that's it. You can see it live on http://buzz.meteor.com There is a button there you should never press.
We're relying on the package autopublish
to automagically sync the entire contents of the Buzz collection with the client.
As people press the button and buzz objects get added to the collection, autopublish
ensure that all connected users see the change.
The problem is we're only interested in buzzes that get added after we load the page. Right now we're loading every buzz ever made, all at once, as the page loads, which is sub-optimal.
Assuming no one ever presses the button, that won't be a problem, but in the spirit of professionalism, let's fix it any way.
The autopublish
package is enabled by default, so let's remove it and handle the data pub/sub syncronisation dance ourselves.
meteor remove autopublish
Now lets create a publish function that only sends records created after a user connects
if (Meteor.isServer) {
Meteor.publish('buzzez-from-now', function () {
return Buzz.find({ createdAt: { $gte: Date.now() }})
})
}
and on the client side, we subscribe to it
if (Meteor.isClient) {
Meteor.subscribe('buzzez-from-now')
}
And that's it. Now don't go getting into any trouble and don't be pressing that button.
Vibrate icon designed by Jetro Cabau Quirós from the Noun Project
All the code on github: https://github.com/meteor-london/buzz
Presented at Meteor London, 18th Sept 2014
by @olizilla & @_alanshaw