Adam Tuttle

Creating Cordova (PhoneGap) Android Prod/Dist Builds on the CLI

My development workflow has been kind of ephemeral lately. We've been using PhoneGap and PhoneGap:Build for quite some time, but we recently started working with Estimote's iBeacon-compatible devices for an upcoming event; and the closed-source Estimote SDK is a dealbreaker for the Build service.

This was a particular pain point for me, having never built PhoneGap apps locally. I was -- and to some extent still am -- a complete Xcode Noob. With enough Google, Stack Overflow, and IRC trolling I was able to get through all of that, but what seemed even less documented was how to make a release build of my android application and automate its signing. Eventually I found that on Stack Overflow too, so I thought I would document it here for you (and future me).

The CLI command to compile a release build for Android is:

cordova build android --release

If you notice, the output of this command, very near the end contains:

   [echo] No and key.alias properties found in
   [echo] Please sign /Users/adam/.../platforms/android/ant-build/Reunion-release-unsigned.apk manually
   [echo] and run zipalign from the Android SDK tools.

The solution, as I found on Stack Overflow, is to create a file named inside the platforms/android/ folder. In it, put two lines:

The first line should have the full path to your .keystore file, and the second line should contain the name of your key alias.

After doing so, the build process will prompt you for your keystore password (twice) during the build and use it to sign and automatically zipalign your binary. Then you'll find it at platforms/android/ant-build/{APPNAME}-release.apk

This .apk file is ready to be submitted to the Play Store.

Published 2014-05-20 @ 08:30 in Android PhoneGap

From the Department of Poorly Chosen Defaults

I've got approaching a dozen PhoneGap powered apps in the Apple App Store and the Google Play Store. I'm pretty familiar with the various reasons your app can get rejected and usually do a fine job of staying within the established boundaries.

I recently ran into an issue with an app that was rejected because it "violates the iOS storage Guidelines." In particular, they said that my app downloaded an unreasonable amount of data and stored it in such a way that it added 6mb+ to the device's iCloud backup. Just in case this ever happens to you, or future me, I thought I would document what I did to resolve this.

As it turns out, more recent versions of PhoneGap include a default value for the BackupWebStorage preference that would appear to be, at least as far as I can tell, poorly chosen. As far as I can tell, this setting tells iCloud to backup the majority of the content (code and other assets!) of the application. That has to be the case, because my app was only downloading a few kilobytes of data -- no way it was getting anywhere near 6mb -- and not even saving that much of it in localStorage: 0.7kb!

To fix this, I added the following preference to my config.xml:

<preference name="BackupWebStorage" value="none"/>

Whether you're building locally or using PhoneGap:Build, adding that line as-is to your config.xml is sufficient.

According to the PhoneGap documentation, the default value is cloud, which of course tells iOS to back stuff (ALL THE THINGS!) up into iCloud... hence my problem. I don't know all of the other use-cases for this setting, but it would seem that this setting could potentially get a lot of people in trouble with Apple.

Hat tip to Max Lynch of the Ionic Framework project for clueing me in to this preference. Thanks for being available in IRC, Max!

Published 2014-05-12 @ 01:02 in Apple PhoneGap

My cf.Objective() 2014 Schedule

As some others have done, I thought I would post my intentions for which cf.Objective() sessions I'd like to attend, and my reasons for doing so.


After a brief layover in Atlanta, I should land in Minneapolis around 5:00pm, just in time to make my way to the hotel and settle in before the Welcome Reception, which is always a good time. The hotel bar is a great venue for this as well, with some billiard tables and lots of standing and sitting room to hang out with the friends you haven't seen for months or possibly since last year's conference.


9:00 am - The opening keynote this year looks like it's going to be really good again. Jen Myers comes from outside of our community and brings a lot of experience and wisdom that I hope we'll all take to heart.

10:15 am - There are a bunch of really great things to kick the conference off, but I think the one I'm most interested in is Dan Wilson's The Top 5 Things You are Doing Today to Hinder Scalability. With our plans for this year, architecture, scalability, and performance is on my mind a lot lately.

11:30 am - I think I'll get the most from Leveling-Up at Javascript: DOM Traversal by Brian Rinaldi. JavaScript is easily the majority of what I write these days, so squeezing every bit of performance possible from it sounds like a good use of my time.

3:00 pm - I asked the community to find someone to present on Running CF on Linux and Pete Frietag stepped up. I'm really eager to see what sort of things I haven't thought about, and hopeful that he's got a simple solution to what I perceive as a black box of torture: Appropriate system/file permissions for a server.

4:15 pm - While I probably won't pick up much new information, I'm planning to attend Sharon DiOrio's Node.js: Why Would Anyone Want to Write Their Own Web Server? In part as moral support, because it's a polarizing topic and I'm on her side (Node is awesome!) but also because I know Sharon is f*%$#ing smart and I'm hoping she can elevate my game in some subtle, and maybe not so subtle ways.


9:00 am - This might be the first time slot where I feel conflicted. It helps that I had a hand in the schedule's organization, but you can never get completely away from this feeling with so much good content to find a spot for. While I would love to attend Kev McCabe's Software Craftsmanship session (his blog series on the same topic was really good), but as a rule of thumb I only allow myself to miss an Elliott Sprehn presentation is when I am speaking at the same time... so I'll be at Web Components are Awesome (and Polymer too).

10:15 am - This is another time slot with conflict for me. I really want to learn more about Angular.js so I would go to Sharon DiOrio's AngularJS: Getting the UI Sugar without the jQuery Pain, but I expect that to be on the simpler end, whereas I think I'll really get a lot out of Ryan Anklam's Stop Making Excuses And Start Testing Your JavaScript! -- so that's where I'll be. I admit it: I believe whole-heartedly in testing, but I don't do enough of it. Because I'm lazy.

11:30 am - I have a pretty strong focus on JavaScript this year, so I think I'll probably go to Leveling-Up at Javascript: Understanding the Confusing Bits by Jason Dean, but the BDD session by Luis also looks interesting.

1:45 pm - I'll be presenting Building Communities: Lessons Learned From 4 Years Running a Successful Open Source CFML Project (and you should be there!)

3:00 pm - I'll be at the CFClient session by Simon Free. Just kidding! Dollars to donuts I'll bet Adam Cameron just did a spit take. I may need a quick breather and a nap before I get back on stage at 4:15, but if I don't, I'll be at Say Goodbye to “It works on my machine” with Chef and Vagrant by Curt Gratz. Vagrant is a really awesome development tool that I don't think enough people are using. I'm not using it enough myself. But I know its power, and I know it tends to evolve pretty quickly, so I'm interested to see what's new.

4:15 pm - I'll be presenting Open Yourself to Closures, an updated version of my CFSummit 2013 presentation. It's introductory / core principles, so if you have never used closures before or if you have but you want to get a better understanding of how and why they work, you should be there!

8:00 pm - Ryan Anklam and I will be hosting a BoF workshop for you to come and take your first baby steps with Node.js. Even if you've dabbled with it before, there's plenty you can learn. This will be a hands-on workshop so bring your laptop and be ready to install Node and get your hands dirty! We'll be introducing you to, and the wealth of knowledge it contains.


9:00 am - I will be up, bright-eyed and bushy tailed, not hung over, and in the front row for Ryan Anklam's Ember.js - A Framework For Building Ambitious Web Applications. As I mentioned in my interview on the CFHour Podcast, I am keen to use Ryan's Ember knowledge to contrast with my own Angular knowledge and make sure I'm leading my company down the right technological path for our future.

10:15 am - Again thinking toward the future of my company, Enterprise Service Bus' are on my mind. How fortuitous, then, that Luis Majano will be presenting Decouple and Scale with Enterprise Messaging

11:30 am - I don't always see eye to eye with Ray Camden, but I do respect him, and sometimes the healthy skepticism that comes from personal conflict helps you see the best in what they're offering. So I'll be at his session, Leveling-Up at Javascript: Organization, Performance & Testing hoping to further hone my JS skills. Note that I'm attending all of the "Level Up your JavaScript" talks -- a very important thread for me this year.

1:45 pm - There are 3 sessions in the final time slot that I would love to attend, but I think a great way to end a long conference is with an eye to the future, so I'll be at FutureJS: An Introduction to ECMAScript 6 “Harmony” by Marcin Szczepanski, learning about what's coming in the future of JavaScript. I'm particularly excited about Generators, but I know there's much more to it than that.

And there you have it. Your complete guide to stalking me for the next week or so. See you there!

Published 2014-05-12 @ 09:30 in cf.Objective()

On cf.Objective() 2014 Scheduling

The schedule for cf.Objective() (just 14 days away!) is almost final. Pending some last minute shuffling to accommodate sessions with higher demand, it's pretty well solidified. How will they know what demand is going to be? That's where you come in.

Head to your friendly neighborhood (App|Play) Store and download ConBop (AppleAndroid). Once installed, enter event code cfo2014. Then indicate your interest in sessions by tapping the star icon next to them in the sessions list.

Important: When you click the star, the app will offer to add the session to your device's calendar. Unless you're already in the U.S. Central time zone, do not say yes; it will use your current local time, resulting in incorrect times when you arrive at the conference! (You can re-apply the star after you arrive to add it to your device calendar, if you like.)

See you there!

Published 2014-04-29 @ 11:44 in cf.Objective()