Building for Android with Cocos2d-X (NDK+JDK) in one step

One Step to Better Code

Recently, I’ve read once again the old but awesome article “Joel Test : 12 steps to better code” (do it now if you haven’t). When developing Don’t Feed the Trolls, I always had a few steps to build a new android version of the game. I made a few scripts but I still had multiple steps. My workflow was:

  1. Copy the resources in the android assets folder
  2. Compile the C++ code with Gygwin
  3. Launch eclipse
  4. Use option Android / Build Signed Package in Eclipse
  5. Type two passwords for signature

I recently improved this workflow, and now it is:

  1. Double click the “build_android.bat” file

Much better!
Here are details of the script.

1. Copying the resources

It’s simple batch script that copies the resources from the multiplatform “Resource” folder (used in cocos2d-x templates) to the assets folder used on Android.

rmdir /S /Q "D:gamedevGamesswg21Devandroidassets"
mkdir "D:gamedevGamesswg21Devandroidassets"
xcopy "D:gamedevGamesswg21DevResource" "D:gamedevGamesswg21Devandroidassets" /S /H
del "D:gamedevGamesswg21Devandroidassetssnd*.wav"

I first delete the existing files. Then I create the directory and copy all my resources. Finally, I remove wav files, as these are used only on the windows version. My multiplatform Resource folder contains sound in formats for all platforms.

2. Compiling the C++ source code

The native C++ code is compiled in cygwin. I spent a lot of time trying to figure out how to run a script from a batch and having it return immediately (with an error code). For the record, I was missing the –login parameter to the bash command. Here is the command I use:

cd "d:gamedevcygwinbin"
bash --login "./swg21.sh"

The swg21.sh is a bash script placed in my home folder, calling cocos2d-x build_native script.

cd /cygdrive/d/gamedev/games/swg21/dev/android
./build_native.sh

build_native.sh is a bash script calling ndk-build after setting up proper environment variables.

3. Compiling the java and creating the signed apk

This was the main step I wanted to optimize from my previous workflow. Running Eclipse just to build a version was really slowing down the whole process. For that part, you have to use ant, as explained in the Google documentation.

cd "D:gamedevGamesswg21Devandroid"
call ant release

The problem was that I was still asked to enter my password to sign the apk. This is fixed by editing the ant.properties file, as shown below (Credit goes to NickT from stackoverflow):

key.store.password=password
key.alias.password=password
key.store=path/to/your.keystore
key.alias=alias

4. Dropbox

I use dropbox to transfer apk to my Android device. Therefore, I need to copy the file to my dropbox folder.

copy "D:gamedevGamesswg21Devandroidbinswg21-release.apk" "C:UsersWin7Dropboxtempswg21.apk"

5. Error checking

Steps 2 and 3 can fail (compile errors). I added some batch script to change the screen color to green when it’s successful, and red if not. Here is the final build_android.bat with error management.

@echo off
@echo "============================================ COPY RESSOURCES"
rmdir /S /Q "D:gamedevGamesswg21Devandroidassets"
mkdir "D:gamedevGamesswg21Devandroidassets"
xcopy "D:gamedevGamesswg21DevResource" "D:gamedevGamesswg21Devandroidassets" /S /H
del "D:gamedevGamesswg21Devandroidassetssnd*.wav"

@echo "============================================ COMPILE NDK"
cd "d:gamedevcygwinbin"
bash --login "./swg21.sh"
IF %ERRORLEVEL% NEQ 0 GOTO FAIL
GOTO SUCCESS
:FAIL
COLOR 40
GOTO END
pause
:SUCCESS

@echo "============================================ COMPILE JDK+Sign"
cd "D:gamedevGamesswg21Devandroid"
call ant release
IF %ERRORLEVEL% NEQ 0 GOTO FAIL

@echo "============================================ COPY FILE TO DROPBOX"
copy "D:gamedevGamesswg21Devandroidbinswg21-release.apk" "C:UsersWin7Dropboxtempswg21.apk"
COLOR 20
:END
pause

Improvements and Conclusion

I’m glad I did this script and don’t understand why I didn’t do it earlier. I now build a new Android apk almost every night.
If you’re working on a team, you might also add source control scripts to get the latest version of your code/resources automatically. Also, my projects path are hardcoded, I should set “swg21″ (the project name) in a command line parameter and use relative paths. I’ll probably do it when I’ll use this script for a second project.
I’ll also do the same thing for iOS when my current project will be closer to release (I’ve read it’s not that trivial to do, we’ll see).
Feel free to share and comment this article here or on twitter.