Introduction
In this article I am going to outline how you can quickly develop an Android Wear smartwatch app using Meteor. Meteor is a full stack Javascript app development platform that can be used to develop reactive web and mobile apps in a very short space of time. To create mobile apps, Meteor uses Cordova and the android.webkit
API, in particular the WebView
class. Those of you who are already au fait with Android Wear may know that it doesn't include the android.webkit
API. "Well then how on earth will your app work Chris?" I hear you cry! Fear not friend, read on and all will be revealed!
This article is primarily aimed at individuals with a background in web development who want to get up and running quickly on Android, and Wear in particular. This means you don't need any Java experience. A bit of knowledge of HTML, Javascript and CSS would be useful to help you debug but if you're able to cut and paste and type a few commands at the console you're good to go!
The app we're going to create is a simple game of noughts and crosses, nothing epic but something that will make you look like you're doing something really important on your fancy smartwatch! I'm developing the app to test on the Sony Smartwatch 3 and all Meteor development is done on Ubuntu 14.04 LTS. If you have a different watch or are developing on a Mac or Windows then you may have to tweak things slightly here and there but it should be straightforward to get up and running. I assume some basic Linux experience (e.g. knowing how to open the console) but if you're having trouble please feel free to ask questions and I'll do my best to help.
Learning Outcomes
By the end of this tutorial you will be able to:
- Install Meteor
- Create a simple Meteor project
- Edit, debug and then run your Meteor project in a browser
- Enable your Meteor project for Android
- Add a Cordova plugin to your Meteor project
- Run your Meteor project on an Android Smartwatch
Installing Meteor
First things first, you need to install Meteor. On Linux and OS X this is as simple as running the following command in the console:
curl https://install.meteor.com/ | sh
On Windows you can get the official Meteor installer from https://install.meteor.com/windows.
Create a Meteor project
With Meteor installed we can now create a new Meteor project. Open the console and in your home directory create a new folder called meteor-projects
and cd
into it:
cd ~
mkdir
meteor-projects
cd meteor-projects
To create a new Meteor project we use the meteor create <project name>
command where <project name>
is replaced by the name of your new project (kinda obvious really!). We're going to call our project "WearOX":
meteor create WearOX
If all has gone well you'll get a success message like the one below:
lf you cd
into the WearOX
directory and then type ls
cd WearOX
ls
you'll see that Meteor has created three new files for you:
At its simplest a Meteor project consists of three files, one which contains HTML code, one which contains Javascript code and one which contains your CSS styling. We'll edit each in turn to get our app up and running.
Edit the HTML
We're going to start by getting our interface looking respectable so we'll first edit the WearOX.html
file. You can use any editor of your choice, I use the open-source Brackets along with the handy Ternific extension which provides hinting and refactoring for Javascript and Meteor (I also use the Brackets Beautify extension which pretties up your Javascript every time you save your code).
Upon opening the file you'll notice the default HTML that Meteor creates for the project:
<head>
<title>WearOX</title>
</head>
<body>
<h1>Welcome to Meteor!</h1>
{{> hello}}
</body>
<template name="hello">
<button>Click Me</button>
<p>You've pressed the button {{counter}} times.</p>
</template>
Most of the HTML tags (e.g. <head> and <body>) here will be familiar to anyone who has done basic web development. You'll notice however that there are some words surrounded by double curly braces {{}} as well as a <template> tag. Any code within a <template> tag is considered to be part of that template, with the template being identified by its name. In this case our template name is "hello". Within the body tags we can 'inject' our template by inserting a set of double curly braces inside of which we put the template name prefixed with the greater than symbol. This means our template will render at the position of the {{> hello}}.
To see how this looks we'll now start our Meteor project by typing meteor in the console:
By default your project runs as a web app on your local machine and can be viewed by opening your browser and navigating to http://localhost:3000.
Your first Meteor project is up and running, just click the button and feel the joy! Okay, so you may not be blown away but this is just a very simple project. We're now going to modify it so that we get our Noughts and Crosses game up and running in the browser before we move it to our Android Wear app.
Rather than write a Noughts and Crosses game from scratch we're going to borrow some code from Stephen Chapman's article on About.com and make some small modifications to get it working in Meteor. We'll leave Meteor running while me make our edits so that we can take advantage of its reactive updates. This basically means that Meteor will look out for changes to our HTML, Javascript and CSS files and will automatically apply those changes to our live app.
We're going to use buttons to represent our three by three Noughts and Crosses board so open the WearOX.html
file in your editor and replace the contents with the following:
<head>
<title>WearOX</title>
</head>
<body>
{{> oxtemplate}}
</body>
<template name="oxtemplate">
<div id="ox">
<button id="ox1">
</button>
<button id="ox2">
</button>
<button id="ox3">
</button>
<button id="ox4" class="brox">
</button>
<button id="ox5">
</button>
<button id="ox6">
</button>
<button id="ox7" class="brox">
</button>
<button id="ox8">
</button>
<button id="ox9">
</button>
</div>
</template>
In the code above we're setting our page title to "WearOX" and within the body of our page we're injecting a template named "oxtemplate". This template is defined in the same file and is simply a <div> that contains nine <button>s with consecutive ids. Buttons ox4 and ox7 have an additional class attribute that will be used to style our board.
Modifying the CSS
When you save WearOX.html
Meteor will update the interface of your app to reflect the above changes and will render the following:
It's not quite looking like a Noughts and Crosses board just yet so we need to now move to editing our WearOX.css file. Open the file in your editor and you'll find the following code:
If you didn't already know then you're getting a subtle hint about what we need to put in it! We're going to use the following CSS to style our board:
#ox {
width: 156px;
height: 156px;
overflow: hidden;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
}
#ox button {
width: 50px;
height: 50px;
float: left;
margin: 1px;
color: #fff;
background-color: #6496c8;
text-shadow: -1px 1px #417cb8;
border: none;
outline: none;
}
.brox {
clear: left;
}
What the above stylings are essentially saying is that within our <div> named "ox", make all buttons 55px by 55px and a lovely shade of blue. The .brox class, which we previously applied to buttons ox4 and ox7 in our HTML file, stops any buttons floating to the left of buttons ox4 and ox7. This gives us a three by three Noughts and Crosses grid. If you save the CSS file and go to your browser you should see it update to reveal our nicely styled grid:
Modifying the Javascript
With our styling complete we can now move on to make our game actually do something. Our WearOX.js file is where the magic happens. Open it in your editor and you'll see the following code:
if (Meteor.isClient) {
Session.setDefault('counter', 0);
Template.hello.helpers({
counter: function () {
return Session.get('counter');
}
});
Template.hello.events({
'click button': function () {
Session.set('counter', Session.get('counter') + 1);
}
});
}
if (Meteor.isServer) {
Meteor.startup(function () {
});
}
Meteor is a full stack platform which means that we can write code that runs on a client, on the server or both. Our templates are rendered on the client side hence we wrap any code related to templates, such as events and helpers, in an if (Meteor.isClient) {}
block so that it doesn't run on the server. Any code that should run on the server but not on the client is wrapped in a if (Meteor.isServer) {}
block. Any code that should run on both doesn't need wrapping in anything!
In more advanced apps you would separate your code into different directories called client
, server
and both
. Meteor knows by the name of the directory where the code should run meaning you need not use Meteor.isClient and Meteor.isServer.
Another thing to note from the above code is that a Meteor helper is simply a function that reactively computes and returns a value. In the example above this means that whenever Session.get('counter')
is called anywhere in the code - for example when the button is pressed to increase the value of the count by one - our 'counter' function is called and returns the new value. In the original HTML you may have noticed a reference to our counter helper wrapped in curly braces i.e. {{counter}}
. This means that our interface automatically updates to display every time a new value is returned by the 'counter' function. Unfortunately the default code is slightly confusing because we have a session variable called 'counter' and also a helper function called 'counter'.
When you get into building more complex apps with Meteor you'll find out how powerful this reactivity can be but for this app we don't need any helpers or template events, just some simple Javascript. We're going to replace the default Javascript with the following code that is reworked from Stephen Chapman's original:
if (Meteor.isClient) {
Template.oxtemplate.rendered = function () {
var turn = 0;
var pos = [];
template = this;
var oxd = [];
for (var i = 1; i < 10; i++) {
oxd[i] = template.find('#ox' + i);
oxd[i].i = i;
oxd[i].onclick = function () {
setit(this.i);
}
}
beginit();
};
}
beginit = function () {
turn = 0;
pos = ['', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '];
for (var i = 1; i < 10; i++) template.find('#ox' + i).innerHTML = '';
}
setit = function (idb) {
var val = template.find('#ox' + idb).innerHTML;
if (val == '') {
turn++;
if (turn % 2 == 1) {
template.find('#ox' + idb).innerHTML = ' X ';
pos[idb] = 'X';
}
if ((winner = win()) != ' ') {
alert(winner + ' wins');
beginit();
return;
}
if (turn == 9) {
alert('draw');
beginit();
return;
}
var cptr = check2();
template.find('#ox' + cptr).innerHTML = ' O ';
pos[cptr] = 'O';
turn++;
if ((winner = win()) != ' ') {
alert(winner + ' wins');
beginit();
return;
}
}
}
check2 = function () {
if (check(2, 3, 1) || check(4, 7, 1) || check(5, 9, 1)) return 1;
if (check(1, 3, 2) || check(5, 8, 2)) return 2;
if (check(1, 2, 3) || check(7, 5, 3) || check(6, 9, 3)) return 3;
if ((check(1, 7, 4) && !check(7, 9, 8)) || check(5, 6, 4)) return 4;
if (check(1, 9, 5) || check(2, 8, 5) || check(3, 7, 5) || check(4, 6, 5)) return 5;
if (check(4, 5, 6) || (check(3, 9, 6) && !check(7, 9, 8))) return 6;
if (check(1, 4, 7) || check(3, 5, 7) || check(8, 9, 7)) return 7;
if (check(7, 9, 8) || check(2, 5, 8)) return 8;
if (check(1, 5, 9) || check(3, 6, 9) || check(7, 8, 9)) return 9;
if (check(1, 9, 2) || check(3, 7, 2)) return 2;
if (check(1, 9, 4) || check(3, 7, 4)) return 4;
if (pos[5] == ' ') return 5;
if (pos[1] == ' ') return 1;
if (pos[3] == ' ') return 3;
if (pos[7] == ' ') return 7;
if (pos[9] == ' ') return 9;
if (pos[8] == ' ') return 8;
if (pos[6] == ' ' && pos[6] == ' ') return 6;
if (pos[4] == ' ') return 4;;
return 2;
}
check = function (x, y, z) {
return (pos[x] == 'X' && pos[y] == 'X' && pos[z] == ' ') || (pos[x] == 'O' && pos[y] == 'O' && pos[z] == ' ');
}
match = function (a, b, c) {
if (pos[a] == 'X' && pos[a] == pos[b] && pos[b] == pos[c]) return 'X';
if (pos[a] == 'O' && pos[a] == pos[b] && pos[b] == pos[c]) return 'O';
return ' ';
}
win = function () {
if (match(1, 2, 3) == 'X' || match(4, 5, 6) == 'X' || match(7, 8, 9) == 'X' || match(1, 4, 7) == 'X' || match(2, 5, 8) == 'X' || match(3, 6, 9) == 'X' || match(1, 5, 9) == 'X' || match(3, 5, 7) == 'X') return ('X');
if (match(1, 2, 3) == 'O' || match(4, 5, 6) == 'O' || match(7, 8, 9) == 'O' || match(1, 4, 7) == 'O' || match(2, 5, 8) == 'O' || match(3, 6, 9) == 'O' || match(1, 5, 9) == 'O' || match(3, 5, 7) == 'O') return ('O');
return ' ';
}
In a nutshell the code above is saying, once the Meteor template called 'oxtemplate' has rendered the DOM on the client, to each button add a click event that calls the setIt
function. The setIt
function adds an 'X' as text on the button that the user clicked (unless it already contains an 'O' or 'X') and then computes the next position that the computer will place its 'O'. After each turn the code determines who, if anyone, has won the game and if there is a winner it displays an alert()
saying who that winner is.
If you save the WearOX.js
file and look at the browser you won't notice a difference until you click on the buttons. You should find that an 'X' appears where you clicked that is quickly followed by an 'O' placed by the computer and so on until one of you wins. Yes, you are indeed playing Noughts and Crosses, so give yourself a clap for getting this far and then we'll move on to shifting your new game over to Android Wear!
Moving to Android Wear
In order to run your code as an Android app, Meteor uses Cordova to wrap your UI in a WebView
from the android.webkit package. To enable our app for Android we need to add the Android platform to our project. To do this you need to have a working Android development environment set up. On Ubuntu, the easiest way to do this is to use Ubuntu Make to install Android Studio and a Java Development Kit. Follow the instructions on the Meteor wiki to get your system set up for Android.
Be sure that you have set the ANDROID_HOME
variable and have added the tools directories to your PATH
. To do this, in the console, edit your ~/.bashrc
file and add the following to the bottom (be sure to replace /path/to/android-sdk
with the real SDK path!) :
export ANDROID_HOME="/path/to/android-sdk"
export PATH="$ANDROID_HOME/platform-tools:$ANDROID_HOME/tools:$PATH"
To apply your changes without restarting the console type:
source ~/.bashrc
Also, ensure that you have Android SDK Platform 22 installed so that you can develop for Wear. Assuming you have set ANDROID_HOME
and edited your PATH
accordingly, you can check which SDKs are installed by running the SDK manager by typing android
at the command prompt.
With Android installed we can move back to our Meteor project. If your app is still running in the console, kill it off by pressing <Ctrl + C>
and then enter the following:
meteor add-platform android
The above command installs all of the necessary tools to build an Android app from your project.
As noted in the introduction, the Android Wear SDK doesn't include the android.webkit package so before we run our Android project we're going to have include something in its place and that something is Crosswalk. Crosswalk allows us to replace the default Android WebView
with a more up to date WebView
based on Google Chromium. In our case it means we can add a WebView
to Android on our Wear device and thus see our Meteor project in action on a Smartwatch.
Crosswalk is Apache Cordova compatible and, fortunately for us, Meteor allows us to easily add any Cordova plugins that we might want to use in our app. In our case we're going to add a plugin directly from the Crosswalk GitHub repository so that we get an up to date build.
In the console type the following:
meteor add cordova:cordova-plugin-crosswalk-webview@https://github.com/crosswalk-project/cordova-plugin-crosswalk-webview.git#cd24c9cf90ed7741b3364cbd8b2b73d9f7dacb93
Yarrgh, what is all that?!
Here we're telling Meteor to add a Cordova plugin (meteor add cordova:
). The text after the colon and before the @ symbol (cordova-plugin-crosswalk-webview
) is the ID of the plugin as specified in the plugin.xml
file in the repository. The text between the @ symbol and the # symbol (https://github.com/crosswalk-project/cordova-plugin-crosswalk-webview.git
) is the URL of the GitHub repository. Finally, the text after the # symbol is the SHA-hash of the Git commit that we wish to use (cd24c9cf90ed7741b3364cbd8b2b73d9f7dacb93
). To find the SHA-hash of the commit, browse the commits in the repository, select the commit you're interested in and you'll see the full hash near the top of the page.
NB. If you ever want to see what Cordova plugins are installed (or any other Meteor plugins from Atmosphere.js) you can use:
meteor list
Running our app on Android Wear
So this is what we've been building up to, we're finally going to run our app on our Android Smartwatch! Well, not quite yet. Before we can there are two things you need to do.
First up, make sure that your Smartwatch has developer options enabled so that Meteor is able to use adb to push the app to the watch. On your watch, go to the Settings menu, scroll down to About and tap it. On the next screen, scroll down until you find the Build Number and then tap it seven times and, hey presto, Developer mode is enabled.
The other thing we need to do is set up Linux to detect our Smartwatch. If you don't already have it, create a new udev
rules file and fix its permissions as follows:
sudo touch /etc/udev/rules.d/51-android.rules
sudo chmod a+r /etc/udev/rules.d/51-android.rules
We now need to add a rule line to this file so that Linux can identify devices manufactured by Sony. Sony's vendor ID is 054c so we pipe the following into our file (a full vendor list and more details on udev
can be found on the Android Developer site):
sudo echo 'SUBSYSTEM=="usb", ATTR{idVendor}=="054c", MODE="0666", GROUP="plugdev"' >> /etc/udev/rules.d/51-android.rules
Be sure to enter your password when prompted. This assumes your account has sudo
privileges. If not, you'll need to log in as the root user to create and edit this file.
Now it's time to connect your Smartwatch to your computer via a USB cable. Once you have done this, type the following at the command prompt:
adb devices
If you've successfully completed the steps above then you should see a message similar to the following:
This means you're finally ready to run your Meteor project on your watch. To run a Meteor project on an Android device we use the following command:
meteor run android-device
Meteor will then download any Cordova plugins you have added, build your app into an Android project and run it on your Smartwatch. Here's a pic of the app running on the watch:
And, just in case you think I've been doing some swift Gimp editing, check out the video on YouTube that shows the app in action.
And that's it! One thing to note before you head off and use Meteor to create your dream Smartwatch app is that adding Crosswalk will increase the app's size quite a lot. This means you can quickly use the limited space on your watch so it's just something to bear in mind when starting your project.
I hope you have found this tutorial useful, feel free to leave comments or ask any questions and I'll do my best to respond.
History
15 Oct 2015: Initial Version uploaded
29 Oct 2015: Fixing spelling and formatting errors