Posted on Jul 4, 2014

World Cup iOS+Android Meteor PhoneGap App, the making-of

WcupPromotion

Coming from a PHP background, for a long time I wanted to test coding in javascript for server side, namely node.js. I am also a Javascript fan, having done some apps in backbone and angular, wrapped in cordova for iOS and Android. Also wanted to test reactive programming. When I knew about Meteor, I realize it was the perfect match.

So I decided to test it on a simple app. The initial example you get from meteor is the leaderboard, so that gave me the idea of a World Cup leaderboard. I crafted some graphics, added Apple’s Gamecenter for some competition, integrated Anthony Terrien’s jQuery Knob, included the meteor packages offline-data (for when the phone is offline) and persistent-session (to keep user scores between sessions). Wrapped it all in cordova using meteor rider and send it to the Apple and Google stores.

Apple had a hard time accepting it. After six (!) rejections, and a personal phone call from the Apple reviewer himself (!), I finally got an approval. Too bad the World Cup is ending.

Had a lot of issues with css on Android, namely having a fixed background image. It’s a very old never fixed Google bug.
I got a way around it, but then, the performance was very, very bad. I found out that removing everything that is next to the url tag solved it. Changing from background: url(myimage.jpg) no-repeat center center fixed; to background-image: url(myimage.jpg); background-position: center center;

Back to meteor, the problem is, for a newbie in this like I was, the docs are not clear at some of the steps one needs to take.

Development and Production Environments

First it is not made clear that there’s a huge difference between the development and the production environment and how we go from one to the other. In PHP we only care to move the files from one to the other, redirect the db and that’s it. Meteor is a different beast.

After you successful installed and created your first app, and while you are developing, you call your app using “meteor” or “meteor &” (to keep it running in the background). Then on your http://myserver:3000 you can see your app running. When you edit the files and save them, meteor detects that and automatically refreshes to reflect the changes you made. (hot code push reload) You can use PhpED, EditPad Pro or other similar tool to remote edit your files, which makes good use of SFTP.

When in development mode, you will notice all your javascript files and not “compiled” and can be clearly seen by anyone. (view source)

Now, when you want to deploy, there are several steps you need to make. First you need to run “meteor bundle”. This will create a archive with all your needed files. Next, unpack those files anywhere you want (in my case to root/bundle) and create a bash startmeteor.sh similar to this one:

#/bin/sh
cd /root
export MONGO_URL=mongodb://localhost:27017/wc
export PORT=3000
export ROOT_URL=http://123.456.789.000:3000/
export DDP_DEFAULT_CONNECTION_URL=http://123.456.789.000:3000/
#export METEOR_SETTINGS=$(<settings.json)
forever start bundle/main.js

When you fell conformable moving from develop to production mode:
stop meteor develop mode: kill `ps ax | grep node | grep meteor | cut -d ' ' -f 1`
start deploy mode: sh startmeteor.sh
stop deploy mode: forever stopall

You will also need to have installed forever first.( npm install -g forever)
You will no longer be able to use hot code push reload. You code is now ‘compiled’ (minified). Check the source code now.

Also, my meteor, once in develop mode, often went down, so I’ve put this on cron:

#!/bin/bash
#
/usr/sbin/lsof -i :3000 | grep LISTEN >/dev/null 2>&1
if [ $? -ne 0 ]
then
kill -9 `ps ax | grep node | grep meteor | awk '{print $1}'` >/dev/null 2>&1
sleep 2
echo `date` : Starting meteor >> /root/startmeteor/log
cd /root/myapp/
/usr/local/bin/meteor &
sleep 2
if `/usr/sbin/lsof -i :3000 | grep LISTEN >/dev/null 2>&1`
then
echo `date` : meteor successfully started >> /root/startmeteor/log
else echo `date` : meteor start failed >> /root/startmeteor/log
fi
fi

Adding a package

What if I want to use another javascript lib? Including it like you do for web pages will not work. You need to add them as a package. Atmosphere is a good place to find already made packages, but you can make your own in case you want to use a lib not already on Atmospherejs. In order to install packages from Atmospherejs you need to install Meteorite.
One thing not on the docs is that in order to have Meteor load a local package you need to add the package and path to your smart.json file, like this:

"packages": {
"meteorpackage1": {},
"meteorpackage1": {},
"myaddedpackage": {
"path": "../meteor/packages/myaddedpackage"
}

If you are out of luck and really need to create a package, here’s a very simple example of a package.js from iscroll: (also check how the iscroll.js itself is tweaked from the original)

Package.describe({
summary: "Make the world iscroll"
});

Package.on_use(function (api) {
api.add_files([‘iscroll.js’], ‘client’);
api.export && api.export(‘IScroll’, ‘client’);
});

Best info I found on how to do this is this link. Shame on me doing a “this” anchor!

Turning it into an app

Now, the best way to do this is to use Cordova/Phonegap. There are several ways to join meteor with cordova, but my favorite is meteor rider. It’s in an early stage of development – I even discovered a bug, which has now been fixed – but it’s already pretty functional.

Using meteor rider, your DOM will be hijacked and fully replaced by the meteor app, so except for some native calls you might like to call before everything loads, in my case, splashscreen, insomnia, all you code will be the meteor app, including the native calls.

That’s why you will need to detect who is loading the page, if it’s the web, the iOS or Android. The best way to do this is using the device cordova plug-in, but you can also just simply test, for instance, if an iOS only plug in is loaded or not. In case of an iOS/Android only app, if not loaded it’s Android. I needed this because the Android version does not have iad, gamecenter, etc.

if (typeof window.plugins.iosonlyplugin !== 'undefined'){
// plugin is available we're on iOS
}

One of the last puzzling issue I encounter when loading the app from the phones was everything working fine except the native calls to the cordova plug-ins. Ends up it was a path issue. I was using, on meteor rider,

this: meteorUrl: "http://123.456.789.000:3000/"
instead of this meteorUrl: "http://123.456.789.000:3000"

Promotion

Will be running today (July the 4th), during the two World Cup matches, a low budget campaign on Facebook. It will be very narrow target, to French and German men who like football and have iphones.
In the end I am just testing if the app has the ability to stick. Wish me luck.

Thanks for reading this far, I hope it will be useful to someone facing the same issues I did. In the meanwhile please give it a try, it’s free.

iPhone Version | Android Version

1 Comments