There are a few main steps to getting this working:
- Install tools - Android SDK (along /w JDK and build-tools), and the NDK
- Configure project - setting up AndroidManifest.xml, adding android_native_app_glue to your project
- Build - setup Android.mk for use with ndk-build, and write a simple build script to pipe it all together
If you haven't already, you'll need to install the Android SDK (which I think includes the JDK? Otherwise grab that as well), the Android NDK, and the SDK build-tools. You can do that using SDK manager. Downloading these will get you the following tools:
- ndk-build (NDK) - for building the final .so file for the .apk
- aapt (build-tools) - this is for packaging your .apk (app) file
- jarsigner (JDK) - for signing the .apk
- keytool (JDK) - for creating a key store for use with jarsigner
- zipalign (build-tools) - for compressing the .apk
- (also ndk-gdb if you intend to debug using that)
The NDK download will also include a couple files you need to link against. These files are called android_native_app_glue.h/c
. They are thoroughly explained in the native-activity sample provided by Google - I highly recommend reading the entire sample!
First you'll want to set up your AndroidManifest.xml
file in the root of your project. Mine is pretty small so I'll just include the whole thing inline:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="digital.panthalassa.hitlist" android:versionCode="1" android:versionName="1.0">
<uses-sdk android:minSdkVersion="22" android:targetSdkVersion="29" />
<uses-permission android:name="android.permission.SET_DEBUG_APP"></uses-permission>
<application android:allowBackup="false" android:fullBackupContent="false" android:icon="@drawable/color_icon" android:label="@string/app_name" android:hasCode="false" android:debuggable="true">
<activity android:name="android.app.NativeActivity" android:label="@string/app_name" android:configChanges="keyboardHidden" android:screenOrientation="portrait">
<meta-data android:name="android.app.lib_name" android:value="native-activity" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
I then recommend that you copy the android_native_app_glue.h
and android_native_app_glue.c
files into your project in prep for linking. Mine were at the following path:
$ANDROID_SDK_ROOT/ndk/21.3.6528147/sources/android/native_app_glue/
($ANDROID_SDK_ROOT
is simply an environment variable I made which points to the root of the SDK). You won't need to include them directly in your main cpp file, you can just define it to link on the command line using ndk-build.
Building isn't too complicated, it just involves a lot of moving pieces.
Firstly it requires writing a configuration file called Android.mk
for use with ndk-build. It is essentially just a make file with a few custom macros useful for Android builds.
In your Android project root (i.e. next to AndroidManifest.xml
), create a directory called jni/
(it must be called jni/
in order for ndk-build to find it!), and within that directory create a file called Android.mk
. Again, the file is super small, so I'll just include the whole thing inline:
LOCAL_PATH := /home/jonny/code/hitlist/code
include $(CLEAR_VARS)
LOCAL_CFLAGS += -Wno-writable-strings -O2
LOCAL_LDLIBS := -llog -landroid
LOCAL_SRC_FILES := $(LOCAL_PATH)/android/android_native_app_glue.c $(LOCAL_PATH)/android_hitlist.cpp
LOCAL_MODULE := native-activity # important caveat, see NB below for details
include $(BUILD_SHARED_LIBRARY)
NB: The LOCAL_MODULE
name must exactly match the name given in the following AndroidManifest.xml
field (specified above):
<meta-data android:name="android.app.lib_name" android:value="native-activity" />
If they don't match, this won't work!
With that in place, you can go about writing a build script which takes all the necessary steps to build an .apk for your desired architecture. I will include my personal build script (with additional comments) in an attached file in this gist. I build on Linux, but it should be a fairly trivial translation from .sh into a batch file or some such! I also have a "run" script which deploys the .apk to an emulator, which I'll include too as a bonus.
Happy coding!