Here's some google documentation about it:
http://developer.android.com/guide/developing/building/building-cmdline.html
"Building and Running from the Command Line
In this document
Building in Debug Mode
Building in Release Mode
Build unsigned
Build signed and aligned
Once built and signed in release mode
Running on the Emulator
Running on a Device
Application Signing
See also
Managing AVDs from the Command Line
Using the Android Emulator
Signing Your Applications
There are two ways to build your application using the Ant build script: one for testing/debugging your application — debug mode — and one for building your final package for release — release mode.
// Sounds reasonable
Regardless of which way you build your application, it must be signed before it can install on an emulator or device—with a debug key when building in debug mode and with your own private key when building in release mode.
// ok
Whether you're building in debug mode or release mode, you need to use the Ant tool to compile and build your project.
// That's what I'm shooting for.
This will create the .apk file that you can install on an emulator or device. When you build in debug mode, the .apk file is automatically signed by the SDK tools with a debug key, so it's instantly ready for installation onto an emulator or attached development device. You cannot distribute an application that is signed with a debug key.
When you build in release mode, the .apk file is unsigned, so you must manually sign it with your own private key, using Keytool and Jarsigner.
// Hmm...have I been building in debug mode? Why do I have to export an unsigned apk manually?
It's important that you read and understand Signing Your Applications, particularly once you're ready to release your application and share it with end-users. That document describes the procedure for generating a private key and then using it to sign your .apk file. If you're just getting started, however, you can quickly run your applications on an emulator or your own development device by building in debug mode.
If you don't have Ant, you can obtain it from the Apache Ant home page. Install it and make sure it is in your executable PATH. Before calling Ant, you need to declare the JAVA_HOME environment variable to specify the path to where the JDK is installed.
Note: When installing JDK on Windows, the default is to install in the "Program Files" directory. This location will cause ant to fail, because of the space. To fix the problem, you can specify the JAVA_HOME variable like this:
set JAVA_HOME=c:\Progra~1\Java\
// I've alway hated that space in Program files. I never name any programming directory with spaces, ever.
The easiest solution, however, is to install JDK in a non-space directory, for example:
c:\java\jdk1.6.0_02"
// Ok, let's see if I can run and from the command line - yes, I get a build failed. Ok, good.
To continue:
"Building in Debug Mode
For immediate application testing and debugging, you can build your application in debug mode and immediately install it on an emulator. In debug mode, the build tools automatically sign your application with a debug key and optimize the package with zipalign.
To build in debug mode:
Open a command-line and navigate to the root of your project directory.
Use Ant to compile your project in debug mode:
ant debug
This creates your debug .apk file inside the project bin/ directory, named
Each time you change a source file or resource, you must run Ant again in order to package up the latest version of the application.
To install and run your application on an emulator, see the following section about Running on the Emulator."
// Let's try it:
$ ant debug
Buildfile: build.xml does not exist!
Build failed
Hmmm...no good.
Obviously, there's no build.xml in the root directory. Why would there be? Probably it can be generated via eclipse, but let's google the error message along with "android" to see what's up.
Ok, I guess I should just follow the directions above.
So, on my Macbook, go to the command line, "cd" to get to the user home.
"$whereis java" reveals java is in "usr/bin/java"
export JAVA_HOME=/usr/bin/java
vim .bash_profile
o, paste it in, :wq
reopen shell
$ env | grep -i java_home
JAVA_HOME=/usr/bin/java
And there it is.
I don't know if that's the problem though.
Try again...
Error: JAVA_HOME is not defined correctly.
We cannot execute /usr/bin/java/bin/java
Let's google some more...
This url:
http://developer.apple.com/library/mac/#qa/qa1170/_index.html
says:
"Many Java applications need to know the location of a $JAVA_HOME directory. The $JAVA_HOME on Mac OS X should be found using the /usr/libexec/java_home command line tool"
$ /usr/libexec/java_home
export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home
But ant gives us the same error message, of course, because there is still not build.xml.
Ah, here we go - from http://www.howtoforge.com/android-buildfile-build.xml-does-not-exist
android update project --target 5 --path /path/to/android/project
change it to target 8,
android update project --target 8 --path ./JlptQuiz5Free
Gets this result:
$ android update project --target 8 --path ./JlptQuiz5Free
Error: Target id '8' is not valid. Use 'android list targets' to get the target ids.
id: 4 or "android-8"
Name: Android 2.2
Type: Platform
API level: 8
Revision: 2
Skins: HVGA, QVGA, WQVGA400, WQVGA432, WVGA800 (default), WVGA854
id: 5 or "android-9"
Name: Android 2.3.1
Type: Platform
API level: 9
Revision: 2
etc..
So, we actually want 4...
There we go:
Updated local.properties
Added file ./JlptQuiz5Free/build.xml
Updated file ./JlptQuiz5Free/proguard.cfg
Ok, well "ant debug" now runs, but it gives it the name of the starting activity, plus debug:
-package-debug-sign:
[apkbuilder] Creating BootStrapActivity-debug-unaligned.apk and signing it with a debug key...
debug:
[echo] Running zip align on final apk...
[echo] Debug Package: /Users/markdonaghue/Documents/workspace/JlptQuiz5Free/bin/BootStrapActivity-debug.apk
And it takes a good 15 seconds to run! Well, that's ok, I'll only be using it for creating releases.
Ok, actually I'll run the "$ android update project --target 4 --path ./myproject" for each project...
Let's continue:
"Building in Release Mode
When you're ready to release and distribute your application to end-users, you must build your application in release mode. Once you have built in release mode, it's a good idea to perform additional testing and debugging with the final .apk.
Before you start building your application in release mode, be aware that you must sign the resulting application package with your private key, and should then align it using the zipalign tool. There are two approaches to building in release mode: build an unsigned package in release mode and then manually sign and align the package, or allow the build script to sign and align the package for you.
Build unsigned
If you build your application unsigned, then you will need to manually sign and align the package.
To build an unsigned .apk in release mode:
Open a command-line and navigate to the root of your project directory.
Use Ant to compile your project in release mode:
ant release
This creates your Android application .apk file inside the project bin/ directory, named
Note: The .apk file is unsigned at this point and can't be installed until signed with your private key.
// This is already a big help - now I don't have to export it manually. But, I might as well continue and just have it
// create the signed apk for me.
Once you have created the unsigned .apk, your next step is to sign the .apk with your private key and then align it with zipalign. To complete this procedure, read Signing Your Applications.
When your .apk has been signed and aligned, it's ready to be distributed to end-users. You should test the final build on different devices or AVDs to ensure that it runs properly on different platforms."
Ok, good. Let's continue.
"Build signed and aligned
If you would like, you can configure the Android build script to automatically sign and align your application package.
// Yes, I like.
To do so, you must provide the path to your keystore and the name of your key alias in your project's build.properties file.
With this information provided, the build script will prompt you for your keystore and alias password when you build in release mode and produce your final application package, which will be ready for distribution.
// Hmmm...keystore *and* alias passwords? Currently I'm only entering the keystore password.
// Are they one and the same? Let's keep going.
Caution: Due to the way Ant handles input, the password that you enter during the build process will be visible. If you are concerned about your keystore and alias password being visible on screen,
// Nope, not concerned.
then you may prefer to perform the application signing manually, via Jarsigner (or a similar tool). To instead perform the signing procedure manually, build unsigned and then continue with Signing Your Applications.
// I'm good.
To specify your keystore and alias, open the project build.properties file (found in the root of the project directory) and add entries for key.store and key.alias. For example:
key.store=path/to/my.keystore
key.alias=mykeystore
// I'm not entirely clear on the alias thing. Actually, if I go to Eclipse and do "project properties, Android tools, export" it shows
// me the path to my current keystore because I've previously entered it.
"/Users/me/Documents/workspace/androidkeys/my-release-key.keystore"
// And the eclipse wizard does prompt me for the alias key as well. Yet, I've been successfully generating release apks without // entering the key twice...
// The jarsigner command I've been running looks like this:
// jarsigner -verbose -keystore my-release-key.keystore "../$1/deploy/$1.apk" alias_name
// Maybe I can check out the build.xml jarsigner command later to see if I can get rid of entering the name twice...
// Actually, I can just run my current script 5 times at this point. Anyway, let's continue.
Save your changes. Now you can build a signed .apk in release mode:
Open a command-line and navigate to the root of your project directory.
Use Ant to compile your project in release mode:
ant release
When prompted, enter you keystore and alias passwords.
Caution: As described above, your password will be visible on the screen.
This creates your Android application .apk file inside the project bin/ directory, named
Ok, I'll build the xml file since it isn't there. Here are the properties, pulled from the export wizard:
/Users/markdonaghue/Documents/workspace/androidkeys/my-release-key.keystore
key.store=/Users/myname/Documents/workspace/androidkeys/my-release-key.keystore
key.alias=alias_name
Ok, let's try it...
Ok, 26 seconds, and it built a signed, zip-aligned apk, but again it's named after the project. And I did, not surprisingly, have to enter the password twice.
So, two questions: why the name, and why two passwords?
It's supposed to be
Let's take a peek inside the build.xml...
Ok, it's taken from here:
Let's google a bit...
Ah, this ought to do it;
http://developer.android.com/guide/developing/projects/projects-cmdline.html
"To update an existing Android project, open a command-line and navigate to the tools/ directory of your SDK. Now run:
android update project --name
--path
So, what I'll do is this:
android update project --name JlptQuiz5Free
Error: The parameter --path must be defined for action 'update project'
Ok,
$ android update project --name JlptQuiz5Free --path ./JlptQuiz5Free/
Updated local.properties
File build.xml is too old and needs to be updated.
Updated file ./JlptQuiz5Free/build.xml
Updated file ./JlptQuiz5Free/proguard.cfg
Too old? Did it do the update? Anyway, lets run the ant release again...
[echo] Signing final apk...
[signjar] Signing JAR: /Users/me/Documents/workspace/JlptQuiz5Free/bin/JlptQuiz5Free-unsigned.apk to /Users/me/Documents/workspace/JlptQuiz5Free/bin/JlptQuiz5Free-unaligned.apk as alias_name
[echo] Running zip align on final apk...
[echo] Release Package: /Users/me/Documents/workspace/JlptQuiz5Free/bin/JlptQuiz5Free-release.apk
That's better. Let's copy the properties file into each of the 10 directories...
Done. Now, we'll figure out how to have a sort of "master" ant run the builds for each of the 10 directories.
I could probably just do it with a simple script, no?
Still, let's follow through this path using ant.
Here's an example of multiple projects, found at http://www.javawhat.com/showWebsiteContent.do?id=525427
So, let's try a couple of projects and see what happens:
Theres really not a dependency, it's just a way to get build all to run them all. A script would already seem better. In fact, I'm going to go with the script right now.
ant ./JlptQuiz5Free/build.xml release
ant ./JlptQuiz4Free/build.xml release
Oh, that's not going to work - build.xml has to be in the same directory as the ant command.
Well, we could always cd in and out. The reason I'm still pushing for the script is I also want to rename the signed jar to get rid of the ".release".
cd ./JlptQuiz5Free/
ant release
cd ../JlptQuiz5Free/
ant release
Yeah, that worked. Still, it's 25 seconds and it takes a while before it gets to the enter password prompt for each one.
I think I'm going to just create the unsigned jar files with and, then use my old signing script. That already has copy and rename in it, anyway. And a lot less output.
Ok, let's do this. I'll delete or rename the build.properties from each directory so that the release will be unsigned. Then do this the first script:
ant ./JlptQuiz5Free/build.xml release
ant ./JlptQuiz4Free/build.xml release
etc.
And, here we go:
-release-nosign:
[echo] No key.store and key.alias properties found in build.properties.
[echo] Please sign /Users/me/Documents/workspace/JlptQuiz5Free/bin/JlptQuiz5Free-unsigned.apk manually
[echo] and run zipalign from the Android SDK tools.
cd ./JlptQuiz5Free/
ant release
cd ../JlptQuiz4Free/
ant release
cd ../JlptQuiz3Free/
ant release
cd ../JlptQuiz2Free/
ant release
cd ../JlptQuiz1Free/
ant release
cd ./JlptQuiz5Full/
ant release
cd ../JlptQuiz4Full/
ant release
cd ../JlptQuiz3Full/
ant release
cd ../JlptQuiz2Full/
ant release
cd ../JlptQuiz1Full/
ant release
Ok, run it and com back in 15 seconds * 10 = 150 seconds - about 2.5 minutes.
I'm back. I made a nice cup of coffee and started reading a book! Imagine.
I'm feeling pretty good about the way this is shaping up. I can run this script and don't have to glued to the laptop waiting for a password prompt to come up in the middle of a sea of text every 30 seconds or so. And then I can run my nice, fast script. Actually, I'll run it 10 times from a separate shell script. But first, let's modify it do the rename and be a bit more generic.
Here's the modified script:
echo "signing jar..."
jarsigner -verbose -keystore ./androidkeys/my-release-key.keystore "./$1/bin/$1-unsigned.apk" alias_name
echo "Checking if APK is verified..."
jarsigner -verify "./$1/bin/$1-unsigned.apk"
# renames to temp
echo "removing old temp file.."
rm -f temp.apk
echo "running zipalign to temp file.."
zipalign -f 4 "./$1/bin/$1-unsigned.apk" temp.apk
echo "moving temp back to original deploy apk"
mv temp.apk "./$1/deploy/$1.apk"
I'm assuming this is now run from the Eclipse's workspace directory, one level above the projects. I like having a separate deploy directory to prevent confusion with other apks that might be kicking around when I upload, but it's really not necessary or anything like that.
Let's test it out. Ok, it's working.
Now, lets finally create another script to call this one with each of the directory names. Actually, I'd feel a bit more comfortable putting these scripts in a subdirectory. For the jarsigner script, that just means putting an extra "." in front of the directory. Same with the ant script, just the first entry changes. I'll create a directory called "genapk"
What would be really cool would be a perl script to change the versionCode in the manifest. Just a global replace. But, I'm putting all this effort into something I'm not planning on changing much. I'll leave it as it is right now.
Here's a nice little script from http://jeffreysambells.com/posts/2010/10/22/a-git-pre-commit-hook-to-update-androidmanifest-xml-versioncode/
# Configuration
# -------------
# The Manifest path is relative to THIS script.
# If you copy-and-paste this into your pre-commit hook
# and your AndroidManifest.xml is in the root of your repo
# then the path would be:
# MANIFEST="../../AndroidManifest.xml"
# If this is in the same directory then it's just:
MANIFEST="AndroidManifest.xml"
# Script DO NOT MODIFY (unless you want to)
declare -x SCRIPTPATH="${0}"
FULLPATH=${SCRIPTPATH%/*}/$MANIFEST
if [ -f $FULLPATH ]
then
LINE=$(grep -o ${FULLPATH} -e 'android:versionCode="[0-9]*"');
declare -a LINE;
LINE=(`echo $LINE | tr "\"" " "`);
VERSION=(${LINE[1]});
INCREMENTED=$(($VERSION+1))
sed "s/android:versionCode=\"[0-9]*\"/android:versionCode=\"${INCREMENTED}\"/" $FULLPATH > $FULLPATH.tmp && mv $FULLPATH.tmp $FULLPATH
echo "Updated android:versionCode to ${INCREMENTED} in ${FULLPATH}";
fi;
It looks like all I have to do is change the path to this:
MANIFEST="../$1/AndroidManifest.xml"
When I go into the code to make a small change, however, eclipse starts generating a ton of warnings like this:
[2011-08-09 21:09:58 - JlptQuiz1Free] Dx class name (com/kanjisoft/jlpt1/free/R) does not match path (classes/com/kanjisoft/jlpt1/free/R.class)
...while parsing classes/com/kanjisoft/jlpt1/free/R.class
...while processing classes/com/kanjisoft/jlpt1/free/R.class
Well, at least the app install ok.
When I run it again, the warnings didn't show up, but the build was slow; I reran it while building and the warnings showed up again. And it seems to lose that comforting "installed apk" message.
This tip from SO http://stackoverflow.com/questions/4163167/convert-class-file-to-dex-file might help:
"dx --dex" can accept some options. For example, "--no-strict" option will skip checking whether path names of input class files match the declared package/class names, so you'll get a different result for WebService.class if you invoke dx with this option
Well, the ant build is really slow due to the use of dx. If Exlipse is now using build.xml, that could explain it. Let move it out and see what happens.
Ah, I see. It's building the whole works space, so it's calling all the builds.
What I can do is make a rename script to rename all the build.xml to xbuild.xml when I'm developing, and vice versa when I'm generating the apks.
cd ../JlptQuiz5Free/
mv build.xml xbuild.xml
cd ../JlptQuiz4Free/
..etc.
Ok, now let's run eclipse..
No, it didn't work.
Well, let's at least move the builds back to their correct names.
It's a livable problem - eclipse seems to install it quickly enough, it's just those warnings. I won't be in there so much, hopefully while I'm doing my IOS thing, so for now I'll just live with out. I can always get into the android build.xml and add that warning if I really get aggravated by it.
Alrighty then - lets run the increment versionCode script.
It didn't work - I think the scriptpath is the problem.
Change to this:
FULLPATH=${SCRIPTPATH%/*}/../$1/$MANIFEST
Nope. Well, I'll finish this up tomorrow. I'm getting a little bleary eyed!
No comments:
Post a Comment