From time to time I got frustrated with Eclipse (update: I no longer use Eclipse). For those who have buggy software or other problems that hinder you from creating an apk file, you can follow these steps apart from opening Eclipse.
Purpose of this page for newcomers: In the past, I used Cordova/PhoneGap to create the debug version of my apps for testing, then turned to Eclipse to create the final apk that Google Play accepts for the store. Play does not accept debug versions of an app. This article gives the steps to use Cordova CLI to create the final apk version that would be uploaded to Google Play or any other app store that accepts apk files.
The information is divided into two sections. The first section is for new, version 1 apps in which a private key and keystore need to be generated. The second section is for version 2+ apps, in which the keystore is already present and needs to be applied to the apk to sign it. Just follow all these steps in the Terminal app – you need open no other software.
If you have Eclipse installed, you already have the tools you need, such as the following.
The Java Development Kit (JDK) uses jarsigner, and should already be installed.
Apache ant is needed. Download it from http://ant.apache.org/bindownload.cgi if you don’t have it. I downloaded the zip version, right-clicked and selected Uncompress. I dragged the /apache-ant-1.9.3 folder to the /Developer folder.
The zipalign tool is found in the Android SDK, so you already have it. If not, download at http://developer.android.com/sdk/index.html. I dragged the uncompressed /android-sdk-mac_x86 folder to the /Developer folder.
Your .bash_profile hidden file at /Users/<name>/.bash_profile should have the path to the zipalign file like this (though you would change it to match your own zipalign path):
Mac OS X 10.9.5 Mavericks on 2010 Mac Mini
cordova -v = 4.0.0 (using cordova, not phonegap)
Installed: cordova, node, npm
Installed: ADT, Eclipse Juno
Signing a First Version Apk Apart from Eclipse
1. Update the AndroidManifest. Open /myApp/platforms/android/AndroidManifest.xml and update. VersionCode is what will display in the store; versionName is for your internal use and won’t be shown: android:versionCode=”10000″ android:versionName=”1.0.0″ (Note on format: “10000” = 1.00.00.)
Make sure the following is accurate (change com.developerName.myApp to your own information here and throughout this page):
Make sure the following is 11 or higher (I choose 19.):
Open /myApp/config.xml and make sure the widget id and version are the same as in AndroidManifest.xml.
2. The following steps create your private key and the keystore file in which to store it. In Terminal, make sure your starting position is within your app’s root folder of /myApp and run the following. (To start commands from your app root folder in Terminal, open the Terminal app, type cd and a space, drag the /myApp folder to Terminal, tap in Terminal to activate its window, then hit Enter.)
keytool -genkey -v -keystore myapp.keystore -alias myapp -keyalg RSA -keysize 2048 -validity 10000
You’ll be prompted to answer several questions. Use only legal characters like letters and numbers, not punctuation. For 2-letter country code, look up this list: http://www.worldatlas.com/aatlas/ctycodes.htm
3. You will then review the data presented. At that point, if any of the information is wrong, type the two letters to re-enter that information. For instance, type cn to change your first and last name. Otherwise, confirm the information by typing “yes.” Then just hit Enter if the password for the following Terminal information will be the same as the previous.
Your keystore file will be located at /myApp/myapp.keystore. This needs to be copied to a safe place ASAP. Your customers will not be able to update to the next version without this file.
4. Copy myapp.keystore to /platforms/android.
Now it’s time to sign the app with the key and create the release version.
5. Open /platforms/android/local.properties (or project.properties) in a text editor.
6. Add these two lines at the end and save, even though it says, “Do not modify this file — YOUR CHANGES WILL BE ERASED!”
7. Still in your /myApp folder in Terminal, run:
cordova build android --release
You’ll be asked for your password twice and it won’t be obfuscated.
8. Your myApp.apk file is put in /myApp/platforms/android/ant-build/CordovaApp-release.apk. (If not there, it may be in /myApp/platforms/android/build/outputs/apk.) This is the file you rename and upload to Google Play.
Signing an Update Version Apk Without Eclipse
This section assumes you’ve already created your keytool and keystore file from your first version, and have the keystore file in a safe place. You won’t follow those steps again.
1.Open /myApp/config.xml and update. Increment the version number.
2. In Terminal, make sure your starting position is within your app’s root folder of /myApp and run the following. (To start commands from your app root folder in Terminal, open the Terminal app, type cd and a space, drag the /myApp folder to Terminal, tap in Terminal to activate its window, then hit Enter.)
3. From your app’s root folder in Terminal:
cordova build android --release
- I once got the error:Error: ENOENT, no such file or directory '/Users/<name>/Documents/AndroidApps/myApp/platforms/android/src/com/developername/myapp'
- I once got the error:Error code 1 for command: ant with args: ... command failed with exit code 8
Solution: remove the android platform and add it back in. Copy your platforms/android/res/drawable folders to a safe location if the icons and splash screens are not already backed up, for the following command will erase that folder.cordova platform remove android cordova platform add android
Now copy back the /res/drawable folder contents and remove the /drawable folders that don’t apply to your app. Go ahead and follow step 3 again.
Another solution I found was to correct my /platforms/android/AndroidManifest.xml file. I had “23” instead of “22” in this line: android:targetSdkVersion=”22.” It was wrong because I did not have he v23SDK installed, but did have the v22 SDK. That resolved the error.
- I once got the error:BUILD FAILED /Users/<name>/Documents/iPhone_Apps/from_Steve/Hymnal/<app-name>/platforms/android/build.xml:90: Cannot find /Users/<name>/android-sdks/tools/ant/build.xml imported from /Users/<name>/Documents/iPhone_Apps/from_Steve/Hymnal/<app-name>/platforms/android/build.xml
Solution: In console, run cordova platform rm android then cordova platform add android and run the command again.
4. Change your /platforms/android/ant-build/CordovaApp-release-unsigned.apk to the final app name by clicking on its name and overwriting it when it gets highlighted. (If not there, it may be in /myApp/platforms/android/build/outputs/apk.)
If that path does not exist, try /platforms/android/build/outputs/apk/android-release-unsigned.apk and change that filename.
5. Move the myApp.apk file and copy the myapp.keystore file to project’s root folder.
6. Change the Terminal prompt to start at your app’s root directory.
7. Run the following in Terminal and follow the prompts to enter your passphrase (the password you used to sign the first apk). myapp.keystore is your keystore name, myApp.apk is the name you put in step 4, and myapp is the alias of your app (see step 6 of the previous section).
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore myapp.keystore myApp.apk myapp
You’ll be asked for your passphrase.
- I once got the error:jarsigner: unable to open jar file: myApp.apk
Solution: move the myApp.apk file to same location as myapp.keystore.
- I once got the error:Error: /Users/<name>/Documents/AndroidApps/myApp/platforms/android/cordova/build: Command failed with exit code 8
Solution: copy your myapp.keystore file to your project’s root directory.
- I once got the error:jarsigner: Certificate chain not found for: myapp-12.0.0. myapp-12.0.0 must reference a valid KeyStore key entry containing a private key and corresponding public key certificate chain.
Solution: I did not have the alias correct (that last “myapp” in the command). I removed the extraneous text from the alias and tried again and it worked.
8. If there were no error messages, verify that it has been signed:
jarsigner -verify -verbose -certs myApp.apk
Output should end with “jar verified.”
- I once uploaded an apk to the Google Play Developer Console and was warned: “Upload failed. You uploaded an APK that is signed with a different certificate to your previous APKs.” Then it showed the SHA1 number series it should have. I had several versions of the keystore file – so which one was the correct one to use?
Solution: I applied the following script to each one to reveal the SHA1 numbers so I could compare them against the ones in the Console window which I had left open. Just run this command from your keystore file’s folder and change the keystore name here to the real keystore file name:keytool -keystore myApp.keystore -list -v
- I received the error:jarsigner: Certificate chain not found for: <app name>. <app name> must reference a valid KeyStore key entry containing a private key and corresponding public key certificate chain.
Solution: I looked carefully and found that my alias did not match the alias revealed in the script above. Once I changed it, it worked fine.
9. Complete your final apk by running zipalign. This script will take your myApp.apk and output the final version, renamed myApp-final.apk:
zipalign -v 4 myApp.apk myApp-final.apk
It should end with “Verification succesful.” [sic] near the end.
I once got the error:-bash: zipalign: command not found
Solution is to download the “19.1.0” SDK, and copy the “zipalign” file to /Developer/adt-bundle-mac-x86_64/sdk/tools. In Eclipse: Windows > Android SDK Manager. Select “Android SDK Build-tools” for “19.1.0” and continue the install process. Shut down Eclipse. The file should be written to /Developer/adt-bundle-mac-x86_64/sdk/build-tools/19.1.0. Copy and paste that file to/Developer/adt-bundle-mac-x86_64/sdk/tools, then run the above zipalign command again.
Your app, myApp-final.apk, is ready to upload. Remember to remove the keystore file from the root directory.