I wrote my wife an app for Christmas

I wrote my wife an app for Christmas.

I got the idea mid-panic attack in the middle of a crowded mall a couple of days before the holiday. I had wandered around in a daze, trying to figure out what I could get her that said exactly the right thing. That thing was “I got you this because I love you (and I thought you might like it (but feel free to return it (because I have no idea what I’m doing.)))”

Heart Icon made with PikazoIn the past I had solved this quandary with the wrong perfume, clothes that didn’t fit and ugly jewelry. Each of those gifts were lovingly unwrapped, received with grace and promptly returned the next week.

As I stood amidst the swirling crowd, I reflexively checked my phone for an answer to my problem. There are at least a thousand apps that promise to pick the best (or at least most profitable) gift for your loved ones. I’m sure there are some sophisticated algorithms behind these apps and untold hours of intern copyediting, but I didn’t have time to get past their on-boarding wizards.

The apps gave me an idea, though. Some of the most memorable and touching gifts are handmade. The gifts I prize the most were made of construction paper smudged with little fingerprints. I’m not an artist or particularly crafty. I’m not a carpenter and I don’t know how to write a hit song. What I do know how to write is, well… javascript mostly.

So, I rolled up my IDE and made my wife a present with javascript (the good parts) and Cordova, the hybrid app platform.

The Code

The idea for the app was pretty straightforward. I would write a list of reasons why I love my wife and the app would present a random item from the list each time it opened.

I built the app using Cordova, which is a tool that will package up an installable app for Android, iOS and other platforms. The app that Cordova builds for us is essentially a thin wrapper around a chrome-less browser window. The UI and functionality of the app is entirely HTML and JavaScript.

The HTML

This an app with pretty limited functionality which relieves us of the burden of thinking about templates and template engines. Instead, we will start with some base HTML and manipulate the DOM in the straightforward way.

1
2
3
4
<div id="app">
<h1>Reason #<span id="reason-number">445</span> Lance Loves Amanda</h1>
<div id="reason-text">She always does her best</div>
</div>

As you can see, we have two elements in the HTML with ids prefaced “reason-” that contain some default text. It is that text that we will dynamically replace.

The JavaScript

The JavaScript starts with an array of reasons. This was the easiest part of the build, as coming up with reasons I love Amanda is as easy as remembering her smile.

If you are already storing reasons you love your significant other in the cloud, you could wire in an API call or lookup options in the WebSQL database that is available in all the mobile operating systems that Cordova supports.

1
2
3
4
5
6
7
8
9
10
11
12
13
// A truncated list of reasons I love my wife...
var reasons = [
 “Amanda always tries her best”,
 “Amanda is nice to me when I’m sick”,
 “Amanda makes pretty babies”,
 “Amanda’s always up for a cuddle”,
 “Amanda is passionate about what she believes in,
 “She is always eager to learn”,
 “She is a fighter”,
 “She puts up with my crazy ideas”,
 “She laughs at my jokes (even the terrible ones),
 “Amanda believes in me”
];

In most tutorials for Cordova apps, there is a section describing the deviceready event. Unlike JavaScript apps in the browser which are largely concerned with access to the DOM, a typical Cordova app will need to wait for confirmation that the code that connects the app to the Device APIs has loaded.

In our app we’re not doing anything that clever and could get by with waiting for the DOM loaded event. However, in the interest of convention and being open to future upgrades, I’ll stick with the deviceready event.

1
2
3
4
5
6
7
8
9
10
11
12
13
var app = {
    initialize: function() {
        document.addEventListener('deviceready', this.showReason, false);
        document.getElementById('app').onclick = this.showReason;
    },
    showReason: function() {
        var reasonNumber = Math.floor(Math.random()*reasons.length),
            reason = reasons[reasonNumber];
        document.getElementById('reason-number').innerHTML = reasonNumber;
        document.getElementById('reason-text').innerHTML = reason;
    }
};
app.initialize();

You’ll notice I bound an extra call to showReason to the click event on the app. This is mostly for debug purposes, as the deviceready event is not called when testing in the browser.

The CSS

As a coder, my design skills range from middling to catastrophic. For most apps and sites that I develop myself I rely heavily on CSS frameworks and templates made by people with an eye for typography and whitespace.

For this app, I searched the Facebook streams of my wife and I for a recent picture of us together. We have kids now, so it was surprisingly difficult to find one with just our smiling mugs. I copied the best one I found to the project directory and placed it as the background for the body.

In this respect, having an audience of exactly one was helpful, as I looked up the screen resolution of my wife’s phone and sized the background image to fit as best it could in portrait and landscape orientations.

To this I added a bit of CSS to center and size the text, using Google Chrome’s helpful device preview feature in Developer Tools to make adjustments. This layer is a prime target for animations and transitions to make the app special. In my version I added a CSS transition to grow and fade in the text when it loads.

Building The App With Cordova

Now that I had a working app, I used Cordova to build an installable app that I could put on her phone. The first step is to install Cordova using npm:

1
npm install --global cordova

Next, navigate to where you store your code and use the cordova create command to initialize a new Cordova project:

1
cordova create loveways com.muddylemon.loveways LoveWays
This will create a new directory with the name loveways in the current working path. The second and third arguments will set the namespace and name of your app in the config.xml file that Cordova uses to build your app.

Inside the directory you will find the standard folders and files for a Cordova project. One of the directories, www, is where our HTML and JavaScript files are served from. In a fresh cordova create there is a default app in www that displays an image and demonstrates listening for the deviceready event. Replace that code with your own and copy over any images or other assets.

Add A Platform

In order to build the app for your loved one’s device, you need to add the matching platform to this project. You will also need to have the right build tools available on your development machine. For example, have Xcode installed and up to date for iOS (don’t forget to install the command line tools!) For android, install the Android Studio software and install the SDKs you need in the SDK manager.

After you’ve prepared your machine, add the platform by running the command:

cordova platform add ios
cordova platform add android

or the one that matches your target device.

I’ve found it helpful to open Xcode or Android Studio and initialize the included emulators before building from Cordova.

Build The Application

At this point you can create a build and see your app running on the target mobile OS! There are a number of discreet build commands in Cordova that can overlap confusingly. For our purposes we can use cordova run <platform> which will cover all the bases from preparing the build, compiling it and installing the app on an emulator.

If you don’t have an emulator open when you call cordova run, one will be opened for you. If you have a device connected to your computer with the developer options turned on, the application will install to your device. The first time this happens is magical.

The Icon

Cordova will use a default icon if you don’t tell it otherwise. It looks like a robot doing push ups. Luckily, replacing the robot icon is simple and really adds some panache to the app. My method, being a graphically challenged person, was looking for a generic heart shape image and then sprucing it up with some tools. You can use Gimp, Photoshop or a similar application to run some interesting filters. Recently I discovered an app that I think is perfect for creating an icon — Pikazo. It is a mobile app that takes one image, the generic heart in my case, and styles it with another image. You can run your icon against Picasso, Basquiat, Bugs Bunny or anything and get a unique and occasionally beautiful result.

After you have an image you want to use, I recommend creating a 512px by 512px copy of it and saving it as icon.png in the www folder of your Cordova project. Then install cordova-icon via npm and run it when you update the icon or the platforms you are building. The script will copy that image to all the proper dimensions and resolutions and save them into the correct place in the platforms folder.

Install Your App

If you’re satisfied with your app and icon, it is time to install it on your loved one’s phone. I’ll leave the details of acquisition to the reader, but once you’ve gotten your hands on his or her unlocked device, resist the urge to snoop and instead turn on Developer Mode and plug it into your computer.

Execute the cordova run <platform> command and watch for any errors. Find the icon and test opening and running the app. You might want to copy the icon to a conspicuous place if you want your user to find it by surprise. I attempted that but eventually had to point it out and watch it sink in as she discovered what the app really was.

More Info

If you want to learn more about the Cordova platform, you can start with the Cordova documentation. I’ve referred to the project as Cordova throughout this article, but you can also find relevant information by searching the brand name Phonegap, which is the commercial version of Cordova owned by Adobe.

If you have any questions or comments, hit me up on twitter @muddylemon.

Lance Cameron Kidwell

16 February 2016

Posted in Coding

In lieu of comments, please talk about this post with smart people at Hacker News Hacker News or, if you're the twittering sort, click this handsome button: