PhoneGap: Compiling a Release APK without using PhoneGap Build
While recently finishing up my first PhoneGap application (which was tailored strictly for the Android platform), I encountered a problem that wasted some of my time. I’m documenting the problem and solution below for the sake of others who may run into the same issue.
The Problem
When you’re compiling a PhoneGap application for release, the PhoneGap team
seems to expect that you’ll use PhoneGap build to package your
application. That was not an option for me, however, because the PhoneGap build
system only allows you to upload your web asset files for compilation (ie,
those that live in app-root/assets/www
). For reasons documented
elsewhere, that didn’t work for me, because I was forced to modify my
application’s main Java file by hand.
Though I assume that this is a fairly common problem, I had a hard time tracking down precisely how to compile an APK for release without using PhoneGap build. Learning how to do so required some sleuthing.
Reversing Cordova
My first step in figuring out how to build a release APK was simply to take a
look at some of the Cordova code, where I noticed that app-root/cordova/BOOM
was simply a wrapper that invoked app-root/cordova/cordova BOOM
. Inspecting
app-root/cordova/cordova
, I then discovered that BOOM
merely invokes ant clean
and ant debug
to generate the debugging APKs.
With that, I knew that ant
was actually doing all of the work behind the
scenes. (This would probably be obvious to a Java developer, but I have
virtually no Java experience.) Once I knew that Cordova was silently invoking
the native Android tool chain for compilation, I began reading the appropriate
SDK documentation.
The Android Build Process
I learned a few things from the Android SDK documentation. The first was that
an Android application must be cryptographically signed before it can be
published to the Google Play store, and that the APKs produced by debug
and
BOOM
were being automatically signed by a debugging key. (I also learned
that APKs that were signed by a debugging key may not be distributed in the
Play store, so don’t waste your time trying to do so.)
I also learned that there are two ways to compile a release APK:
First Approach
- Generate a debug APK
- Sign it
- Align it
Second Approach
- Generate an unsigned APK from scratch
- Sign and align it in one step
(The concept of “alignment” was new to me, but it seems to be some form of compression/file arrangement whereby asset bytes are aligned in some specified way. My important takeaway here wasn’t the details - about which I really didn’t care - but that this was a step that needed to be done.)
Simply put, that first approach didn’t work for me. I had a recurring problem whereby the APK that was supposed to be unsigned was not signing correctly. (At least, that’s what this thread on Stack Overflow led me to believe.) Not wanting to waste time, I moved on and tried the second approach.
The Solution
My first step in successfully building a release APK was to create a private key with which I could sign the application. I used a shell command modeled after the following to generate a new key:
keytool -genkey -v -keystore my-release-key.keystore -alias alias_name \
-keyalg RSA -keysize 2048-validity 10000
The resultant key is a private key. Do not distribute it with your application!
I then added the following two lines to app-root/ant.properties
:
key.store=/path/to/my-release-key.keystore
key.alias=alias_name
(Obviously, you would substitute your actual key name, path, and alias above.)
I was then able to compile a release APK using:
jarsigner -verbose -sigalg MD5withRSA -digestalg SHA1 -keystore
my-release-key.keystore my_application.apk alias_name
With this I had a release APK that I was able to successfully upload to the Play store for distribution.