In this chapter, we will take a tour of the main command-line tools, specifically related to the creation and packaging of Android applications. We will learn how to install and configure Android NDK on Microsoft Windows, Apple OS X, and Ubuntu/Debian Linux, and how to build and run your first native application on an Android-based device. Usage of command-line tools to build your projects is essential for cross-platform mobile development using C++.
Note
This book is based on the Android SDK revision 24.3.3 and the Android NDK r10e. The source code was tested with Android API Level 23 (Marshmallow).
Our main focus will be the command-line centric and platform-independent development process.
To start developing native C++ applications for Android in a Microsoft Windows environment, you will need some essential tools to be installed on your system.
Start NDK development for Android using the following list of all the prerequisites you will need:
The Android SDK: You can find this at http://developer.android.com/sdk/index.html. We use revision 24.
The Android NDK: You can find this at http://developer.android.com/tools/sdk/ndk/index.html. We use version r10e.
The Java Development Kit (JDK): You can find this at http://www.oracle.com/technetwork/java/javase/downloads/index.html. We use Oracle JDK Version 8.
Apache Ant: You can find this at http://ant.apache.org. This is a tool used to build Java applications.
Gradle: You can find this at https://www.gradle.org. Compared to Ant, this is a more modern Java build automation tool capable of managing external dependencies.
The current versions of these tools will run on Windows without using any intermediate compatibility layer; they do not require Cygwin any more.
As much as it pains us to write this, Android SDK and NDK should still be installed into folders that do not contain any whitespaces in their names. This is a limitation of build scripts within the Android SDK; the unquoted environment variables content are split into words based on tab, space and newline characters.
We will install the Android SDK to D:\android-sdk-windows
, the Android NDK to D:\ndk
, and other software to their default locations.
In order to compile our portable C++ code for Windows, we need a decent toolchain. We recommend using the latest version of the MinGW from the Equation package available at http://www.equation.com. You can choose 32- or 64-bit versions as you go.
Once all the tools are in their folders, you need to set environment variables to point to those install locations. The JAVA_HOME
variable should point to the Java Development Kit folder:
JAVA_HOME="D:\Program Files\Java\jdk1.8.0_25"
The NDK_HOME
variable should point to the Android NDK installation folder:
NDK_HOME=D:\NDK
The ANDROID_HOME
should point to the Android SDK folder:
ANDROID_HOME=D:\\android-sdk-windows
Both NDK and SDK will have new versions from time to time, so it might be helpful to have the version number on the folder name and manage NDK folders per project if necessary.
Installation of Android development tools on OS X is straightforward. First of all, you will need to download the required official SDK and NDK packages from http://developer.android.com/sdk/index.html. As we are going for command-line tools, we can use the SDK Tools Only package available at http://dl.google.com/android/android-sdk_r24.0.2-macosx.zip. As for the NDK, OS X Yosemite works with the 64-bit Android NDK, which can be downloaded from http://developer.android.com/tools/sdk/ndk/index.html.
We will install all these tools into the user's home folder; in our case, it is /Users/sk
.
To get Apache Ant and Gradle, the best way would be to install the package manager Homebrew from http://brew.sh and bring in the required tools using the following commands:
$ brew install ant $ brew install gradle
This way you will not be bothered with installation paths and other low-level configuration stuff. The following are the steps to install packages and set path for them:
Note
Since the notion of this book is doing stuff from the command line, we will indeed do so the hard way. However, you are encouraged to actually visit the download page, http://developer.android.com/sdk/index.html, in your browser and check for updated versions of the Android SDK and NDK.
Download the Android SDK for OS X from the official page and put it into your home directory:
>curl -o android-sdk-macosx.zip http://dl.google.com/android/android-sdk_r24.0.2-macosx.zip
Unpack it:
>unzip android-sdk-macosx.zip
Then, download the Android NDK. It comes as a self-extracting binary:
>curl -o android-ndk-r10e.bin http://dl.google.com/android/ndk/android-ndk-r10e-darwin-x86_64.bin
So, just make it executable and run it:
>chmod +x android-ndk-r10e.bin >./android-ndk-r10e.bin
The packages are in place. Now, add paths to your tools and all the necessary environment variables to the
.profile
file in your home directory:export PATH=/Users/sk/android-ndk-r10e:/Users/sk/android-ndk-r10e/prebuilt/darwin-x86_64/bin:/Users/sk/android-sdk-macosx/platform-tools:$PATH
Use these variables within Android scripts and tools:
export NDK_ROOT="/Users/sk/android-ndk-r10e" export ANDROID_SDK_ROOT="/Users/sk/android-sdk-macosx"
Edit the
local.properties
file to set up the paths on a per-project basis.
Installation on Linux is as easy as its OS X counterpart.
Note
Indeed, Linux development environment is truly native for all kinds of Android development since all the toolchains and Android Open Source Project are based on Linux tools.
Here, we will point out just some differences. First of all, we don't need to install Homebrew. Just go with the available package manager. On Ubuntu, we prefer using apt
. The following are the steps to install the packages as well as set path on Linux:
Let's start with updating all
apt
packages and installing the default Java Development Kit:$ sudo apt-get update $ sudo apt-get install default-jdk
Install the Apache Ant build automation tool:
$ sudo apt-get install ant
Install Gradle:
$ sudo apt-get install gradle
Download the official Android SDK which suits your version of Linux from http://developer.android.com/sdk/index.html, and unpack it into a folder in your home directory:
$ wget http://dl.google.com/android/android-sdk_r24.0.2-linux.tgz $ tar –xvf android-sdk_r24.0.2-linux.tgz
Download the official NDK package suitable for your Linux, 32- or 64-bit, and run it:
$ wget http://dl.google.com/android/ndk/android-ndk-r10e-linux-x86_64.bin $ chmod +x android-ndk-r10e-linux-x86_64.bin $ ./android-ndk-r10e-linux-x86_64.bin
The executable will unpack the content of the NDK package into the current directory.
Now you can set up the environment variables to point to the actual folders:
NDK_ROOT=/path/to/ndk ANDROID_HOME=/path/to/sdk
Let's start with the lowest level and create a template for our applications buildable with Apache Ant. Every Android application which is to be built using Apache Ant should contain a predefined directories structure and configuration .xml
files. This is usually done using Android SDK tools and IDEs. We will explain how to do it by hand to let you know the machinery behind the curtains.
Tip
Downloading the example code
You can download the example code files from your account at http://www.packtpub.com for all the Packt Publishing books you have purchased. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.
For this book, the source code files can be downloaded or forked from the following GitHub repository as well: https://github.com/corporateshark/Mastering-Android-NDK
The directory structure of our minimalistic project looks like the following screenshot (see the source code bundle for the complete source code):

We need to create the following files within this directory structure:
res/drawable/icon.png
res/values/strings.xml
src/com/packtpub/ndkmastering/App1Activity.java
AndroidManifest.xml
build.xml
project.properties
The icon icon.png
should be there, and currently contains a dummy image of an Android application:

The file strings.xml
is required to make use of the Android localization system. In the manifest AndroidManifest.xml
, we use the string parameter app_name
instead of the actual application name. The file strings.xml
resolves this parameter into a human readable string:
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">AntApp1</string> </resources>
The Java source code of the minimal buildable application is in the App1Activity.java
file:
package com.packtpub.ndkmastering; import android.app.Activity; public class App1Activity extends Activity { };
The rest three files, AndroidManifest.xml
, build.xml
, and project.properties
, contain the description of the project necessary for Ant to build it.
The manifest AndroidManifest.xml
is as follows:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.packtpub.ndkmastering" android:versionCode="1" android:versionName="1.0.0">
Our application will require Android 4.4 (API Level 19) and is tested with Android 6.0 (API Level 23):
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" />
Most of the examples in this book will require OpenGL ES 3. Let's mention it here:
<uses-feature android:glEsVersion="0x00030000"/> <application android:label="@string/app_name" android:icon="@drawable/icon" android:installLocation="preferExternal" android:largeHeap="true" android:allowBackup="true">
Here is the name of the main activity:
<activity android:name="com.packtpub.ndkmastering.App1Activity" android:launchMode="singleTask"
We want a fullscreen application in the landscape orientation:
android:theme="@android:style/Theme.NoTitleBar.Fullscreen" android:screenOrientation="landscape"
Our application can be started from the system launcher. The displayable name of the application is stored in the app_name
parameter:
android:configChanges="orientation|keyboardHidden" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
Note
You can read the official Google documentation on the application manifest at http://developer.android.com/guide/topics/manifest/manifest-intro.html.
The file build.xml
is much simpler and will resemble mostly what Android tools would generate:
<?xml version="1.0" encoding="UTF-8"?> <project name="App1" default="help"> <loadproperties srcFile="project.properties" /> <fail message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through an env var" unless="sdk.dir"/> <import file="${sdk.dir}/tools/ant/build.xml" /> </project>
There is a difference to Android SDK Tools, since we don't use ant.properties
here. This was done just for the sake of simplicity and just has an educational purpose.
The same situation exists with the file project.properties
, which contains platform-specific declarations:
target=android-19 sdk.dir=d:/android-sdk-windows
Now, our first application (which does not even contain any native code yet) is ready to be built. Use the following one-liner to build it:
$ ant debug
If everything was done correctly, you should see the tail of the output similar to the following:

To install an .apk
file from the command line, run adb install -r bin/App1-debug.apk
to install the freshlybuilt .apk
on your device. Start the application from your launcher (AntApp1) and enjoy the black screen. You can use the BACK key to exit the application.
Gradle is a more versatile Java building tool compared to Ant, which lets you handle external dependencies and repositories with ease.
Note
We recommend that you watch this video from Google available at https://www.youtube.com/watch?v=LCJAgPkpmR0 and read this official command-line building manual available at http://developer.android.com/tools/building/building-cmdline.html before proceeding with Gradle.
The recent versions of Android SDK are tightly integrated with Gradle, and Android Studio is built using it as its build system. Let's extend our previous 1_AntApp
application to make it buildable with Gradle.
First, go to the root folder of the project, and create the build.gradle
file with the following content:
buildscript { repositories { mavenCentral() } dependencies { classpath 'com.android.tools.build:gradle:1.0.0' } } apply plugin: 'com.android.application' android { buildToolsVersion "19.1.0" compileSdkVersion 19 sourceSets { main { manifest.srcFile 'AndroidManifest.xml' java.srcDirs = ['src'] resources.srcDirs = ['src'] aidl.srcDirs = ['src'] renderscript.srcDirs = ['src'] res.srcDirs = ['res'] assets.srcDirs = ['assets'] } } lintOptions { abortOnError false } }
After this, run the command gradle init
. The output should be similar to the following:
>gradle init :init The build file 'build.gradle' already exists. Skipping build initialization. :init SKIPPED BUILD SUCCESSFUL Total time: 5.271 secs
The subfolder .gradle
will be created in the current folder. Now, run the following command:
>gradle build
The tail of the output should look as follows:
:packageRelease :assembleRelease :assemble :compileLint :lint Ran lint on variant release: 1 issues found Ran lint on variant debug: 1 issues found Wrote HTML report to file:/F:/Book_MasteringNDK/Sources/Chapter1/2_GradleApp/build/outputs/lint-results.html Wrote XML report to F:\Book_MasteringNDK\Sources\Chapter1\2_GradleApp\build\outputs\lint-results.xml :check :build BUILD SUCCESSFUL Total time: 9.993 secs
The resulting .apk
packages can be found in the build\outputs\apk
folder. Try installing and running 2_GradleApp-debug.apk
on your device.
Let's stick to the topic of this book and write some native C++ code for our template application. We will start with the jni/Wrappers.cpp
file, which will contain a single function definition:
#include <stdlib.h> #include <jni.h> #include <android/log.h> #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "NDKApp", __VA_ARGS__)) extern "C" { JNIEXPORT void JNICALL Java_com_packtpub_ndkmastering_AppActivity_onCreateNative( JNIEnv* env, jobject obj ) { LOGI( "Hello Android NDK!" ); } }
This function will be called from Java using the JNI mechanism. Update AppActivity.java
as follows:
package com.packtpub.ndkmastering; import android.app.Activity; import android.os.Bundle; public class AppActivity extends Activity { static { System.loadLibrary( "NativeLib" ); } @Override protected void onCreate( Bundle icicle ) { super.onCreate( icicle ); onCreateNative(); } public static native void onCreateNative(); };
Now, we have to build this code into an installable .apk
package. We need a couple of configuration files for this. The first one, jni/Application.mk
, contains the platform and toolchain information:
APP_OPTIM := release APP_PLATFORM := android-19 APP_STL := gnustl_static APP_CPPFLAGS += -frtti APP_CPPFLAGS += -fexceptions APP_CPPFLAGS += -DANDROID APP_ABI := armeabi-v7a-hard APP_MODULES := NativeLib NDK_TOOLCHAIN_VERSION := clang
We use the latest version of the Clang compiler—that is 3.6, as we write these lines, and the armeabi-v7a-hard
target, which enables support of hardware floating point computations and function arguments passing via hardware floating point registers resulting in a faster code.
The second configuration file is jni/Android.mk
, and it specifies which .cpp
files we want to compile and what compiler options should be there:
TARGET_PLATFORM := android-19 LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := NativeLib LOCAL_SRC_FILES += Wrappers.cpp LOCAL_ARM_MODE := arm COMMON_CFLAGS := -Werror -DANDROID -DDISABLE_IMPORTGL ifeq ($(TARGET_ARCH),x86) LOCAL_CFLAGS := $(COMMON_CFLAGS) else LOCAL_CFLAGS := -mfpu=vfp -mfloat-abi=hard -mhard-float -fno-short-enums -D_NDK_MATH_NO_SOFTFP=1 $(COMMON_CFLAGS) endif LOCAL_LDLIBS := -llog -lGLESv2 -Wl,-s LOCAL_CPPFLAGS += -std=gnu++11 include $(BUILD_SHARED_LIBRARY)
Here, we link against OpenGL ES 2, specify compiler switches to enable the hardware floating point for non-x86 targets and list the required .cpp
source files.
Use the following command from the root folder of the project to build the native code:
>ndk-build
The output should be as follows:
>ndk-build [armeabi-v7a-hard] Compile++ arm : NativeLib <= Wrappers.cpp [armeabi-v7a-hard] SharedLibrary : libNativeLib.so [armeabi-v7a-hard] Install : libNativeLib.so => libs/armeabi-v7a/libNativeLib.so
The last thing is to tell Gradle that we want to pack the resulting native library into the .apk
. Edit the build.gradle
file and add the following line to the main
section of sourceSets
:
jniLibs.srcDirs = ['libs']
Now, if we run the command gradle build
, the resulting package build\outputs\apk\3_NDK-debug.apk
will contain the required libNativeLib.so
file. You can install and run it as usual. Check the line Hello Android NDK! printed into the Android system log with adb logcat
.
We learned how to use the command line to create Android applications with the native code. Let's put the final stroke on the topic of the command-line tools and learn how to prepare and sign the release version of your application.
The detailed explanation of the signing procedure on Android is given in the developer manual at http://developer.android.com/tools/publishing/app-signing.html. Let's do it using Ant and Gradle.
First of all, we need to rebuild the project and create a release version of the .apk
package. Let's do it with our 3_NDK
project. We invoke ndk-build
and Apache Ant using the following commands:
>ndk-build >ant release
The tail of the output from Ant looks as follows:
-release-nosign: [echo] No key.store and key.alias properties found in build.properties. [echo] Please sign F:\Book_MasteringNDK\Sources\Chapter1\3_NDK\bin\App1-release-unsigned.apk manually [echo] and run zipalign from the Android SDK tools. [propertyfile] Updating property file: F:\Book_MasteringNDK\Sources\Chapter1\3_NDK\bin\build.prop [propertyfile] Updating property file: F:\Book_MasteringNDK\Sources\Chapter1\3_NDK\bin\build.prop [propertyfile] Updating property file: F:\Book_MasteringNDK\Sources\Chapter1\3_NDK\bin\build.prop [propertyfile] Updating property file: F:\Book_MasteringNDK\Sources\Chapter1\3_NDK\bin\build.prop -release-sign: -post-build: release: BUILD SUCCESSFUL Total time: 2 seconds
Let's do the same thing with Gradle. Maybe you have already noticed when we run gradle build there is a 3_NDK-release-unsigned.apk
file in the build/outputs/apk
folder. This is exactly what we need. This will be our raw material for the signing procedure.
Now, we need to have a valid release key. We can create a self-signed release key using keytool
from the Java Development Kit using the following command:
$ keytool -genkey -v -keystore my-release-key.keystore -alias alias_name -keyalg RSA -keysize 2048 -validity 10000
This will ask us to fill out all the fields necessary for the key:
Enter keystore password: Re-enter new password: What is your first and last name? [Unknown]: Sergey Kosarevsky What is the name of your organizational unit? [Unknown]: SD What is the name of your organization? [Unknown]: Linderdaum What is the name of your City or Locality? [Unknown]: St.Petersburg What is the name of your State or Province? [Unknown]: Kolpino What is the two-letter country code for this unit? [Unknown]: RU Is CN=Sergey Kosarevsky, OU=SD, O=Linderdaum, L=St.Petersburg, ST=Kolpino, C=RU correct? [no]: yes Generating 2048 bit RSA key pair and self-signed certificate (SHA1withRSA) with a validity of 10000 days for: CN=Sergey Kosarevsky, OU=SD, O=Linderdaum, L=St.Petersburg, ST=Kolpino, C=RU Enter key password for <alias_name> (RETURN if same as keystore password): [Storing my-release-key.keystore]
Now, we are ready to proceed with the actual .apk
package signing. Use the jarsigner
tool from the Java Development Kit to do this:
>jarsigner -verbose -sigalg MD5withRSA -digestalg SHA1 -keystore my-release-key.keystore 3_NDK-release-unsigned.apk alias_name
This command is interactive, and it will require the user to enter the keystore
and the key passwords
. However, we can provide both passwords as arguments to this command in the following way:
>jarsigner -verbose -sigalg MD5withRSA -digestalg SHA1 -keystore my-release-key.keystore -storepass 123456 –keypass 123456 3_NDK-release-unsigned.apk alias_name
Of course, passwords should match with what you have entered while creating your release key
and keystore
.
There is one more important thing left before we can safely proceed with publishing our .apk
package on Google Play. Android applications can access uncompressed content within .apk
using memory-mapped files and mmap()
system calls, yet mmap()
may imply some alignment restrictions on the underlying data. We need to align all uncompressed data within .apk
on 4-byte boundaries. The Android SDK has the zipalign
tool to do this, as seen in the following command:
>zipalign -v 4 3_NDK-release-unsigned.apk 3_NDK-release.apk
Now, our .apk
is ready to be published on Google Play.
This book continues the idea from our previous book Android NDK Game Development Cookbook, Packt Publishing: the possibility of cross-platform development using the principle What You See (on a desktop PC) is What You Get (on a mobile device). Most of the application logic can be developed and tested in a familiar desktop environment such as Windows with all necessary tools at hand, and this can be built for Android using the NDK whenever necessary.
To organize and maintain the cross-platform C++ source code, we need to split everything into platform-specific and platform-independent parts. Our Android-specific native code will be stored in the jni
subfolder of the project, exactly as we did in our previous minimalistic example. The shared platform-independent C++ code will go into the src-native
subfolder.
TeamCity is a powerful continuous integration and deployment server, which can be used to automate your Android application builds. This can be found at https://www.jetbrains.com/teamcity.
Note
TeamCity is free for small projects that require no more than 20 build configurations and 3 build agents and is absolutely free for open source projects. Ask for an open-source license at https://www.jetbrains.com/teamcity/buy.
The server installation procedure is straightforward. Windows, OS X, or Linux machine can be used as the server or a build agent. Here, we will show how to install TeamCity on Windows.
Download the latest version of the installer from https://www.jetbrains.com/teamcity/download and run it using the following command:
>TeamCity-9.0.1.exe
Install all components and run it as Windows Service. For simplicity, we will run both the server and the agent on a single machine, as shown in the following screenshot:

Choose the desired TeamCity server port. We will use the default HTTP port 80. Run the TeamCity Server and Agent services under the SYSTEM
account.
Once the server is online, open your browser and connect to it using the address http://localhost
. Create a new project and a build configuration.
Note
To work with TeamCity, you should put the source code of your project into a version control system. Git and GitHub will be a good choice.
If your project is already on GitHub, you can create a Git VCS root pointing to the URL of your GitHub repository, like this https://github.com/<your login>/<your project>.git
.
Add a new command-line build step and type the content of the script:
ndk-build ant release
You can also add signing using jarsigner
here and use the zipalign
tool to create the final production .apk
.
Now, go to the General Settings step and add an artifact path to bin/3_NDK-release.apk
. The project is ready for continuous integration.
In this chapter, we learned how to install and configure the essential tools for Android native development using the command line, and how to write Android application basic configuration files manually without falling back to graphical IDEs. In the subsequent chapters, we will practice these skills and build some projects.