4.7 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.4
La preuve mono-ABI de 0-pre.2 a validé que assembleDebug déclenche correctement le build Rust/SDL3 ARM64 sans orchestrateur Python préalable.
0-pre.3 a validé le graphe sur les deux ABI 64 bits. 0-pre.4 élargit le même mécanisme à la matrice Android complète encore supportée :
arm64-v8a
armeabi-v7a
x86_64
x86
pour Snake et Reflex :
:<game>:assembleDebug
-> buildDebugSasedevRustArm64V8a
-> buildDebugSasedevRustArmeabiV7a
-> buildDebugSasedevRustX8664
-> buildDebugSasedevRustX86
-> quatre sources jniLibs générées
-> APK Debug universal
Chaque arbre ABI contient :
build/generated/sasedevNative/debug/<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)
Il ne faut pas appeler scripts/build_android_rust.py avant ces tâches. Le script Python historique reste temporairement versionné jusqu'à la fermeture complète du chemin natif en 0-pre.5, après preuve du chemin release/AAB.
Les outputs natifs restent sous Android/<module>/build/ et ne sont jamais versionnés.
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. Ces smokes ne changent pas le minSdk, qui reste un axe séparé et sera consolidé avec l'AAB/compatibilité dans 0-pre.5.
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.