Android Internals¶
This page records the current Android implementation path. Android is a Supported Kanama target on the Godot 4.7 stable baseline; the API/build flow is less settled than the desktop path.
What Works¶
Nine Kanama demo exports are Android smoke targets (the eight starter/creeps demos plus Bunnymark). On 2026-06-26, the Godot 4.7 stable demo matrix passed on Pixel 7 with debug APK exports, and Starter-Kit-Match3 also passed the R8-minified release smoke with Kanama's PanamaPort fork:
godot-demo-2d-dodge-the-creepsStarter-Kit-3D-PlatformerStarter-Kit-Match3godot-demo-3d-squash-the-creepsStarter-Kit-FPSStarter-Kit-Racinggodot-4-3d-character-controller-tutorialgodot-4-3d-third-person-controller
The 3D Platformer and third-person controller runs are stronger signals because they exercise larger scenes, Android input overlays, and gameplay warmup paths. The exported APK path:
- loads the Android Godot plugin AAR,
- loads
libkanama_bootstrap.sofrom the APK, - captures the Android JVM through JNI,
- initializes the Kanama GDExtension,
- registers
KanamaScriptLanguage, - registers the
.ktresource loader, - loads project Kotlin scripts,
- reaches
OnGodotMainLoopStarted, and - renders the 3D scene through Godot's OpenGL compatibility renderer.
This proves the Kanama runtime path on Android, including the forked-PanamaPort minified path. Android is Supported on 4.7 stable; release builds require Android 13+ (debug down to Android 9), and the release path depends on Kanama's PanamaPort fork.
PanamaPort¶
The Android implementation uses a forked
PanamaPort artifact, published via
JitPack:
com.github.falcon4ever.PanamaPort:Core:0.1.3-kanama-r8.4.
Upstream PanamaPort v0.1.3 miscompiles under Godot 4.7's R8 because its
Android linker uses Java pattern switches over sealed storage/layout types. The
fork rewrites the affected switch sites to explicit instanceof chains and is
published to the configured local Maven repository for Android exports. Keep the
fork diff small and retire it when the upstream artifact carries the fix.
Desktop vs Android FFM¶
Desktop Kanama uses JDK 25 and java.lang.foreign.
Android does not run a desktop JDK inside the game. The Android runtime uses
ART, and the Android build maps the Kanama FFM-facing code to
PanamaPort's com.v7878.foreign
package.
The build tools are also separate from the runtime:
- Desktop development currently uses JDK 25.
- Godot's Android Gradle export flow is run with JDK 21.
- Godot 4.7 stable Android export templates require Android SDK platform API 36, build-tools 36.1.0, and NDK 29.0.14206865.
- The exported Android game runs on ART and PanamaPort, not on a desktop JVM.
Implementation Shape¶
The current Android implementation lives under android/godot-plugin, split
into two AAR modules (task 36; mirrors desktop's kanama.jar /
kanama-scripts.jar shape):
:plugin— runtime AAR (project-agnostic,KanamaAndroid.debug.aar): a Godot Android plugin class, a small Java bootstrap that loadslibkanama_bootstrap.so, the Android native bootstrap library, the remapped Kanama runtime + annotations sources, and a.gdextensionfile marked as an Android AAR plugin. Builds with no consumer project (assembleAndroidPluginAar), which is whatpackageMobileAddonAndroidships.:scripts— scripts AAR (per project,KanamaAndroidScripts.debug.aar): the consumer project'skotlin-src/scripts and generated KSP registrars, remapped identically and compiled against the runtime classes (compileOnly(project(":plugin"))). The runtime.gdapwritten byinstallAndroidPluginAarreferences it as alocal=dependency, so Godot's export adds both AARs and they dex into the same APK classloader — registrar lookup needs no loader-aware path.
Both modules copy sources into generated Android source trees through the same
PanamaPort compatibility remap, shared in buildSrc (KanamaAndroidRemap).
The remap is deliberately guarded per module: auditAndroidKanamaSources
(runtime) and auditAndroidKanamaScriptSources (scripts, plus the pre-remap
demo-source audit) fail the Android build if stale desktop-only APIs or
incorrectly rewritten Kotlin callback calls appear in the generated trees.
R8 note: the runtime AAR's consumer-rules.pro applies APK-wide, so its keeps
for net.multigesture.kanama.generated.** and **.KanamaRegistry cover the
scripts AAR's classes too — no second rules file is needed.
The demo project needs Android entries in addons/kanama/kanama.gdextension:
[configuration]
android_aar_plugin = true
[libraries]
android.debug.arm64 = "libkanama_bootstrap.so"
android.release.arm64 = "libkanama_bootstrap.so"
android.debug.x86_64 = "libkanama_bootstrap.so"
android.release.x86_64 = "libkanama_bootstrap.so"
The Android AAR also includes matching .gdextension metadata. The project file
uses Android entries so Godot's export scanner recognizes the extension for
Android instead of warning that no arm64 library exists.
Current Boundaries¶
The current Android path is intentionally narrow:
- The Android source remap is a guarded Gradle step rather than a dedicated source-set design.
- Some JVM APIs used on desktop have Android-compatible replacements.
MethodHandle.invoke(...)uses Android-compatible handling throughinvokeWithArguments(...).- Demo Kotlin sources are audited before remap for nullable callback invocation
such as
callback?.invoke(), which would otherwise be rewritten like a low-level method-handle call. - The emulator's OpenGL compatibility path can differ visually from desktop rendering. In the 3D Platformer smoke, geometry and gameplay render, but the skybox/background is darker than the upstream desktop screenshot. Logcat also reports unsupported ASTC textures being converted at runtime.
- The current validated demo exports use Godot's OpenGL Compatibility renderer on Android. Desktop can continue using its normal renderer.
- Godot Android can also use Vulkan through the Mobile renderer; Kanama's Android preview has been validated through OpenGL Compatibility.
- Mobile polish is per demo: screen size, orientation, touch input, and UI scaling are separate from the core runtime path.
- Physical devices can expose first-use hitches when gameplay first instantiates scenes, decodes audio, starts particles, or builds generated meshes. Demo ports should warm up these resources during startup when Android smoke shows a hitch that is not visible on desktop.
The smoke script force-stops the launched package on exit so emulator runs do not leave demo processes alive after validation.
Validation Shape¶
Android validation uses the normal demo folders plus Android export metadata,
the Kanama Android plugin AAR, adb install, logcat checks, screenshots, and a
forced package stop after the run. Keep stable support wording pending until
the matching APK smoke matrix passes; physical device validation remains a
stronger platform claim.