# 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 : ```text prefab/modules/SDL3/libs/android./libSDL3.so ``` Elle accepte aussi `jni//libSDL3.so`, puis un fallback Prefab univoque. Pour chaque ABI elle : 1. extrait `libSDL3.so` depuis l'AAR dans un répertoire temporaire de linkage ; 2. stage `libSDL3.so` dans les `jniLibs` générés du variant ; 3. lance `cargo ndk` avec exactement une feature jeu ; 4. stage `libgame_android_entrypoint.so` dans le même arbre généré ; 5. 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 : ```text 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.3 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` élargit ce même graphe à : ```text arm64-v8a x86_64 ``` pour Snake et Reflex : ```text ::assembleDebug -> buildDebugSasedevRustArm64V8a -> buildDebugSasedevRustX8664 -> deux sources jniLibs générées -> APK Debug universal ``` Chaque arbre ABI contient : ```text build/generated/sasedevNative/debug//jniLibs// ├── libSDL3.so └── libgame_android_entrypoint.so ``` Depuis la racine : ```bash 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.4`. Les outputs natifs restent sous `Android//build/` et ne sont jamais versionnés. ## Smoke appareil Le premier APK universal doit être inspecté mécaniquement avant installation. Il doit contenir exactement les couples attendus pour `arm64-v8a` et `x86_64`, sans dépendre de `armeabi-v7a` ou `x86`. Le plan prévoit ensuite un smoke sur l'AVD x86_64 disponible et sur l'appareil ARM64 réel. Ces smokes attestent le packaging multi-ABI ; ils ne changent pas le `minSdk`, qui reste un axe séparé et sera consolidé avec l'AAB/compatibilité dans `0-pre.4`. ## 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`.