Tutorial 82: Android Build and Deployment
Android NDK setup
# Install via Android Studio SDK Manager, or command-line:
sdkmanager "ndk;26.1.10909125"
export ANDROID_NDK=$HOME/Android/Sdk/ndk/26.1.10909125
SDL3 Android project template
SDL3 provides a complete Android project template in SDL/android-project/. Copy it and add
your CNA sources to the JNI layer:
cp -r $CNA_ROOT/third_party/SDL/android-project ./MyAndroidGame
cd MyAndroidGame
# Add your C++ sources to app/jni/src/
CNA CMake integration
# app/jni/CMakeLists.txt
cmake_minimum_required(VERSION 3.20)
project(MyGame CXX)
set(CMAKE_CXX_STANDARD 23)
# SDL3 is provided by the Android project template
find_library(SDL3_LIB SDL3 PATHS ${SDL3_DIR}/lib/${ANDROID_ABI})
add_library(MyGame SHARED
main.cpp
# your other sources
)
target_include_directories(MyGame PRIVATE
${CNA_INCLUDE_DIR}
${SDL3_INCLUDE_DIR}
)
target_link_libraries(MyGame PRIVATE
${SDL3_LIB}
android
log
EGL
GLESv3
)
ARM64-v8a target
Build for arm64-v8a (AArch64) as the primary Android ABI. This covers all Android devices
from 2014 onward. Add armeabi-v7a for older 32-bit devices if needed.
cmake -S . -B build-android \
-DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \
-DANDROID_ABI=arm64-v8a \
-DANDROID_PLATFORM=android-24 \
-DCNA_GRAPHICS_BACKEND=EASYGL
OpenGL ES 3.0 on Android
All Android devices from API level 18+ support OpenGL ES 3.0. CNA's EASYGL backend targets GLES 3.0 which
matches perfectly. Declare the requirement in AndroidManifest.xml so the Play Store filters
out incompatible devices:
<uses-feature android:glEsVersion="0x00030000" android:required="true" />
TouchPanel (needs hardware validation)
CNA exposes TouchPanel for multi-touch input on Android. The API mirrors XNA's
TouchCollection but requires a real device for proper validation — the emulator's touch
simulation is unreliable for multi-finger gestures.
auto touches = TouchPanel::GetState();
for (auto& loc : touches) {
// loc.Position is in screen pixels, loc.State is Pressed/Moved/Released
HandleTouch(loc.Position, loc.State);
}
Accelerometer on Android
SDL3 exposes the device accelerometer through sensor events. CNA wraps this in the
Accelerometer class, mirroring the XNA API.
#include "Microsoft/Xna/Framework/Input/Accelerometer.hpp"
Accelerometer::IsSupported(); // returns true on Android with sensor
AccelerometerReading reading = Accelerometer::GetCurrentReading();
// reading.Acceleration is a Vector3 in m/s²
// X: left/right tilt, Y: forward/back tilt, Z: gravity (~9.8 face-up)
APK packaging
# Build debug APK
cd MyAndroidGame
./gradlew assembleDebug
# Install on connected device
adb install -r app/build/outputs/apk/debug/app-debug.apk
adb shell am start -n com.example.mygame/.MainActivity
# Build release APK (requires signing key)
./gradlew assembleRelease
Gradle configuration
// app/build.gradle
android {
compileSdk 34
defaultConfig {
applicationId "com.example.mygame"
minSdk 24
targetSdk 34
versionCode 1
versionName "1.0"
externalNativeBuild {
cmake {
abiFilters "arm64-v8a", "armeabi-v7a"
arguments "-DCNA_GRAPHICS_BACKEND=EASYGL"
cppFlags "-std=c++23"
}
}
}
externalNativeBuild {
cmake {
path "jni/CMakeLists.txt"
version "3.20.0"
}
}
}