6.4 KiB
Build Rust Android natif
Contrat SDL
SDLActivity charge SDL3, puis game_android_entrypoint, et invoque le symbole SDL_main.
Le crate Rust game-android-entrypoint est un cdylib. Il est compilé avec exactement une feature métier lors du packaging d'une application :
reflex;snake.
Le même nom de bibliothèque native peut être utilisé dans les deux APK puisque chaque module Android possède son propre ensemble de jniLibs générés.
SDL3 AAR et Prefab
L'AAR officiel SDL3 expose ses bibliothèques natives avec Prefab. Pour chaque ABI, la logique Gradle commune cherche d'abord :
prefab/modules/SDL3/libs/android.<abi>/libSDL3.so
Elle accepte aussi jni/<abi>/libSDL3.so, puis un fallback Prefab univoque. Pour chaque ABI elle :
- extrait
libSDL3.sodepuis l'AAR dans un répertoire temporaire de linkage ; - stage
libSDL3.sodans lesjniLibsgénérés du variant ; - lance
cargo ndkavec exactement une feature jeu ; - stage
libgame_android_entrypoint.sodans le même arbre généré ; - vérifie la présence des deux bibliothèques avant de rendre l'output au variant AGP.
Les jniLibs générés sont déclarés à la Variant API via variant.sources.jniLibs.addGeneratedSourceDirectory. Gradle possède ainsi la dépendance entre le packaging Android et le build natif au lieu d'exiger une commande préalable séparée.
Toolchain
Le contrat projet utilise :
AGP 9.4.0
Gradle minimum 9.6.0
JDK runtime >= 17, fourni par l'environnement
Java source/target 17
compileSdk 36
minSdk 21
NDK 28.2.13676358 / r28c
SDL3 AAR 3.4.16
cargo-ndk requis côté développeur
Android/settings.gradle compare GradleVersion.current() au minimum projet 9.6.0. Le projet n'épingle donc pas une distribution Gradle : un Gradle local plus récent est accepté tant qu'il satisfait le minimum.
Le projet Android natif n'impose pas JAVA_HOME. Le JDK courant du shell/IDE exécute Gradle ; java -version et gradle --version sont relevés pendant les gates. Le niveau de bytecode/source Java de la glue reste explicitement 17, indépendamment du JDK de build.
cargo-ndk détecte le NDK désigné pour le sous-processus via ANDROID_NDK_HOME. La tâche Gradle résout cette valeur à partir de ANDROID_HOME ou ANDROID_SDK_ROOT et de androidNdkVersion; aucun ANDROID_NDK_HOME global n'est requis.
État 0.3.3-0-pre.5
0-pre.4 a validé les quatre ABI sur Snake et Reflex : arm64-v8a, armeabi-v7a, x86_64 et x86. Le même mécanisme Gradle est désormais enregistré pour toutes les variantes Android, et pas seulement Debug.
Pour Debug :
:<game>:assembleDebug
-> buildDebugSasedevRust<Abi>
-> cargo ndk build
-> APK Debug universal
Pour Release/AAB :
:<game>:bundleRelease
-> buildReleaseSasedevRust<Abi>
-> cargo ndk build --release
-> AAB Release multi-ABI
Chaque arbre généré contient :
build/generated/sasedevNative/<variant>/<abi>/jniLibs/<abi>/
├── libSDL3.so
└── libgame_android_entrypoint.so
Depuis la racine :
java -version
(cd Android && gradle --version)
(cd Android && gradle :game-snake-poc:assembleDebug)
(cd Android && gradle :game-reflex-poc:assembleDebug)
(cd Android && gradle :game-snake-poc:bundleRelease)
(cd Android && gradle :game-reflex-poc:bundleRelease)
Le builder historique scripts/build_android_rust.py est retiré : il n'existe plus de chemin natif Android qui stage des bibliothèques dans src/main/jniLibs. Les sorties natives sont exclusivement générées sous build/.
Pages mémoire 16 KB
La validation porte sur les deux dimensions requises pour les appareils 64 bits concernés par la contrainte Google Play 16 KB :
- segments ELF des
.soarm64-v8aetx86_64avec un alignementLOADau moins2**14, contrôlés parllvm-objdump -pdepuis le NDK configuré ; - alignement ZIP de l'APK avec
zipalign -c -P 16 -v 4.
AGP 9.4.0 est supérieur au plancher 8.5.1 documenté pour le packaging 16 KB et NDK r28c produit les nouvelles bibliothèques 64 bits avec alignement 16 KB par défaut. Cette propriété ne dispense pas de contrôler libSDL3.so, qui est précompilée dans l'AAR.
Les ABI 32 bits armeabi-v7a et x86 restent dans le package pour compatibilité ancienne et peuvent conserver des segments ELF 2**12 ; cela ne constitue pas un échec de l'exigence Play 16 KB, explicitement portée sur les appareils 64 bits.
Pour l'AAB, les huit bibliothèques doivent être présentes sous base/lib/<abi>/. Lorsque bundletool est disponible, bundletool dump config --bundle=<aab> peut compléter la vérification du mode d'alignement du bundle.
La preuve runtime utilise une image Android 15/API 35 x86_64 ps16k et retient adb shell getconf PAGE_SIZE comme contrôle de la taille de page du device. 16384 est le résultat attendu ; une valeur KernelPageSize lue dans un VMA particulier de /proc/<pid>/smaps n'est pas utilisée comme substitut à ce contrôle.
Plancher Android
Le contrat est consolidé à Android 5.0 / API 21 :
minSdk 21dans chaque application ;sasedevRustAndroidApi = 21pourcargo ndk;- SDL3 documente API 21 comme minimum Android ;
- la gate
0-pre.5a validé un smoke réel sur Android 5.0/API 21 x86 : installation de l'APK universal et démarrage deSnakeActivityréussis.
Smoke appareil
L'APK universal doit être inspecté mécaniquement avant installation. Il doit contenir les deux bibliothèques natives pour chacune des quatre ABI : arm64-v8a, armeabi-v7a, x86_64 et x86.
Le smoke réel reste effectué sur les architectures matériellement disponibles : AVD x86_64 et appareil ARM64. Les ABI 32 bits sont néanmoins exigées au build et dans l'APK ; leur exécution réelle dépend de la disponibilité d'un appareil/AVD 32 bits. Le minSdk 21 est consolidé en 0-pre.5; les smokes disponibles servent de preuve runtime complémentaire et ne redéfinissent pas ce plancher.
Exception FFI Rust
Rust 2024 exige un attribut unsafe pour imposer un nom de symbole d'export. Le projet autorise donc exclusivement #[unsafe(export_name = "SDL_main")] dans game-android-entrypoint. Cette exception ne permet ni bloc unsafe, ni fonction unsafe, ni déréférencement des pointeurs argc/argv.