Building the Game for Android

Category: SDL Adventure Game

This post was written with AI assistance.

The game now builds as a native Android app. make android produces a debug-signed APK you can install directly on a phone, and a GitHub Actions workflow builds one on every push to main and uploads it as a downloadable artifact. Same C code, no web view involved: the NDK compiles the exact sources the desktop build uses into a shared library, and SDL’s stock SDLActivity loads it and calls SDL_main.

The pool scene running on Android in the emulator: Gina next to the
sunscreen bottle, the goggles and float placeholders wiggling, letterboxed
inside the phone screen.

Why the port was one #ifdef

SDL2 treats Android as a first-class platform, so the question was never “can it run” but “how much of the code assumes a desktop”. The answer turned out to be: one function. The desktop main wrapper is now skipped on Android — SDLActivity calls SDL_main itself — and that is the entire diff to the game.

Three properties the code already had did the heavy lifting:

The build

android/ is a trimmed instance of SDL2’s own android-project template: a small Gradle project whose Android.mk lists the same engine and adventure sources as the desktop Makefile. Two scripts do the setup. One downloads the pinned SDL2 / SDL2_image / SDL2_mixer / SDL2_ttf release sources — each ships its own Android.mk, and every optional decoder beyond WAV and PNG is switched off. The other mirrors the shipped asset layers into the APK. Both outputs are git-ignored; nothing is vendored.

The result is an 18 MB APK: five shared libraries (SDL2, the three satellites, and the game) plus 171 assets. CI builds it with the runner’s preinstalled SDK and NDK — the whole workflow is checkout, fetch, sync, gradle assembleDebug, upload.

The screenshot above is the APK running in the Android emulator — in software emulation, since the build machine has no KVM, which is also why the session that produced it involved a “System UI isn’t responding” dialog and a lot of waiting. On real hardware the game runs the same code with GPU acceleration.

Not done yet: a launcher icon (it ships with the stock Android one), reading the device locale (Android has no $LANG, so it falls back to Italian — the right default for this game), and release signing for an actual store listing.