Tuesday, December 4, 2012

Continuous Integration for Mobile Apps with Jenkins: A Note on Android NDK Builds

When blogging recently about how to do continuous integration for Android mobile apps, I realized that I had forgotten to cover one important detail: how to configure Jenkins to perform builds of an Android application that uses the Android NDK (Native Development Kit).  This isn't something that applies to every Android app, but there are certain types of apps that benefit from the use of native-code languages such as C/C++ as described here.  The DroidFish app for Android, which is based on the classic Stockfish chess engine and which I have been using as an example in these blogs, is a case in point: the original Stockfish project was built using C/C++ and a couple of key components of the DroidFish application are implemented as native libraries and called via Android JNI.

If you are a Java programmer and don't expect to be writing any native code (but want to know how to get the application to build and run correctly), then all you really need to know is the following: unlike the SDK, the Android NDK isn't automatically downloaded by the Jenkins Android Emulator Plugin so you need to configure Jenkins to pull this down into the build workspace yourself.  There's a good case for a Jenkins plugin to do just that and I'm happy to write one - in which case, I'll update this blog with the details.  In the meantime, it's fairly easy to use the Execute Shell and EnvInject plugins to do the job, like in this example:



You can find the correct download link for your target environment (Windows/MacOS/Linux) from the Android NDK Download page.  Note how we use the built-in Jenkins $WORKSPACE environment variable to set a custom environment variable (ANDROID_NDK) to point to the location of the NDK install.  Then all you need to do is add a custom_rules.xml file - the standard Android Ant build.xml contains a placeholder to include this automatically - that references it, like so:

<?xml version="1.0" encoding="UTF-8"?>
<project name="custom_rules" default="-pre-build">
    <property file="local.properties" />

    <property environment="env"/>
    <property name="ndk.dir" value="${env.ANDROID_NDK}"/>
    <property name="ndk.cmd" value="ndk-build"/>

    <target name="-pre-build">
        <exec executable="${ndk.dir}/${ndk.cmd}" failonerror="true">
            <arg line=""/>
        </exec>
    </target>
    <target name="-pre-clean">
        <exec executable="${ndk.dir}/${ndk.cmd}" failonerror="false">
            <arg line="clean"/>
        </exec>
    </target>
</project>


That will cause the NDK build utility (ndk-build) to run whenever the project is cleaned/built.  You can see the result if you look at the -pre-build Ant target in the console output of this example build.

Native Code in the DroidFish Application

If you are interested in understanding how native code is actually used in the DroidFish application, open the DroidFish project (I have a copy on GitHub) using Eclipse/ADT and take a look in the DroidFish/jni folder - that's the default location for native Android code.  Open up the Android.mk make files and you'll see that there are three native-code components, which get built in DroidFish/libs:
  1. stockfish: this is the main chess engine (the 'brain' of the app), which is built as a separate 32-bit ELF executable for the different taget architectures with the include $(BUILD_EXECUTABLE) directive and copied to the DroidFish/assets folder to be included in the .apk archive.
  2. gtb.so: this is a shared library that manages the Gaviota Endgame Tablebases - these are special databases which provide the computer with perfect information about every possible endgame with a certain number of pieces (http://en.wikipedia.org/wiki/Endgame_tablebase), built with the include $(BUILD_SHARED_LIBRARY) directive.
  3. nativeutils.so: another, smaller shared library that provides a couple of utility functions for setting permissions and properties for the stockfish engine.
The two shared libraries are loaded with System.loadLibrary() and the stockfish engine is started with java.lang.ProcessBuilder.  You can see these native-code components (with the Android.mk makefile for the stockfish engine) in this screenshot of the Eclipse/ADT project:


Mark Prichard, Senior Director of Product Management
CloudBees


Mark Prichard speaks and blogs regularly as an evangelist for CloudBees and Platform as a Service. He came to CloudBees after 13 years at BEA Systems and Oracle, where he was product manager for the WebLogic Platform. A graduate of St John's College, Cambridge and the Cambridge University Computer Laboratory, Mark works for CloudBees in Los Altos, CA.  Follow Mark on Twitter and via his blog Clouds, Bees and Blogs.


Follow CloudBees:

   

No comments:

Post a Comment