0.3.3-0-pre.3

This commit is contained in:
2026-09-21 10:32:31 +02:00
parent f770f99a4a
commit 5854ac3d07
16 changed files with 1004 additions and 107 deletions

View File

@@ -1,5 +1,5 @@
<!-- file: docs/development/006-ANDROID_RUST_NATIVE_BUILD.md -->
<!-- version: 2 -->
<!-- version: 4 -->
# Build Rust Android natif
@@ -12,95 +12,95 @@ Le crate Rust `game-android-entrypoint` est un `cdylib`. Il est compilé avec ex
- `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 répertoire `jniLibs`.
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 `arm64-v8a`, la structure attendue est notamment :
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.arm64-v8a/libSDL3.so
prefab/modules/SDL3/libs/android.<abi>/libSDL3.so
```
Le script `scripts/build_android_rust.py` accepte cette structure officielle et conserve un fallback `jni/<abi>/libSDL3.so` pour compatibilité.
Elle accepte aussi `jni/<abi>/libSDL3.so`, puis un fallback Prefab univoque. Pour chaque ABI elle :
Pour chaque application, le script :
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.
1. extrait `libSDL3.so` depuis l'AAR ;
2. l'utilise comme bibliothèque de liaison pour le build Rust ;
3. copie `libSDL3.so` dans le `jniLibs/<abi>/` du module Android ;
4. lance `cargo ndk` ;
5. vérifie la présence de `libgame_android_entrypoint.so`.
Ainsi, `SDLActivity` dispose au runtime de `libSDL3.so` et de la bibliothèque Rust applicative.
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
SDL Android requiert actuellement SDK 35 ou ultérieur, NDK r28c ou ultérieur et API minimale 21. La baseline projet conserve `compileSdk 36`, `minSdk 21` et l'AAR SDL3 3.4.16.
Installer au minimum :
```bash
rustup target add aarch64-linux-android
cargo install cargo-ndk
```
NDK de référence :
Le contrat projet utilise :
```text
r28c = 28.2.13676358
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
```
Avec le SDK manager :
`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.
```bash
"${ANDROID_HOME}/cmdline-tools/latest/bin/sdkmanager" "ndk;28.2.13676358" "platform-tools"
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
```
`cargo-ndk` détecte un NDK installé par Android Studio ou utilise `ANDROID_NDK_HOME` lorsqu'il est défini.
pour Snake et Reflex :
Pour utiliser directement `adb` :
```bash
export PATH="${ANDROID_HOME}/platform-tools:${PATH}"
```text
:<game>:assembleDebug
-> buildDebugSasedevRustArm64V8a
-> buildDebugSasedevRustX8664
-> deux sources jniLibs générées
-> APK Debug universal
```
Cet export peut être ajouté au fichier de configuration shell local de la machine.
Chaque arbre ABI contient :
## Build
```text
build/generated/sasedevNative/debug/<abi>/jniLibs/<abi>/
├── libSDL3.so
└── libgame_android_entrypoint.so
```
Depuis la racine :
```bash
python3 scripts/build_android_rust.py reflex
python3 scripts/build_android_rust.py snake
java -version
(cd Android && gradle --version)
(cd Android && gradle :game-snake-poc:assembleDebug)
(cd Android && gradle :game-reflex-poc:assembleDebug)
```
Puis :
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`.
```bash
cd Android
gradle :game-reflex-poc:assembleDebug
gradle :game-snake-poc:assembleDebug
cd ..
```
Les bibliothèques générées sous `Android/*/src/main/jniLibs/` sont des artefacts de build et ne sont pas versionnées.
Les outputs natifs restent sous `Android/<module>/build/` et ne sont jamais versionnés.
## Smoke appareil
Préflight :
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`.
```bash
adb version
adb devices
```
Puis installation/lancement des APK si un appareil ou émulateur est disponible.
L'absence de `adb` ou d'appareil n'est pas un défaut fonctionnel du projet ; elle bloque uniquement le smoke appareil.
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

View File

@@ -1,5 +1,5 @@
<!-- file: docs/plans/003-V0_3_3_ANDROID_NATIVE_MULTI_ABI_PLAN.md -->
<!-- version: 1 -->
<!-- version: 2 -->
# Plan 0.3.3 — Android SDL3 natif multi-ABI et packaging Gradle
@@ -36,8 +36,8 @@ Les décisions de cadrage `0-pre.1` sont :
```text
AGP 9.4.0
Gradle 9.6.0 à épingler par wrapper lors de l'implémentation
JDK 17
Gradle >= 9.6.0, version système acceptée si supérieure
JDK >= 17, fourni par l'environnement ; JDK 25 candidat validable
compileSdk 36
targetSdk 36
minSdk candidat 21
@@ -52,6 +52,16 @@ splits ABI hors chemin par défaut
Le `minSdk 21` est fondé sur le plancher Android actuellement documenté par SDL3, pas sur la seule valeur historique du dépôt. Le `targetSdk 36` est maintenu pour la politique Google Play actuelle.
### Révision de toolchain après `0-pre.2`
La preuve mono-ABI a réussi avec le wrapper Gradle `9.6.0` et JDK 17. Après cette validation, la décision projet est de ne pas transformer ces valeurs de preuve en versions exactes imposées au chemin SDL3 natif :
- AGP `9.4.0` conserve Gradle `9.6.0` comme minimum ;
- un Gradle système plus récent est autorisé et doit être affiché dans la gate ;
- le JDK runtime doit satisfaire Gradle/AGP (`>= 17`) mais provient de l'environnement ;
- le niveau Java de la glue Android reste `sourceCompatibility/targetCompatibility = 17` ;
- les contraintes JDK/Gradle du POC Tauri restent locales à ce POC et ne pilotent pas Android SDL3 natif.
Le pipeline devra aussi vérifier la compatibilité 16 KB des bibliothèques natives finales. AGP 9.4 et NDK r28c fournissent le socle requis, mais le prébuild SDL3 doit être contrôlé dans l'APK/AAB produit.
## Ownership cible
@@ -85,7 +95,7 @@ La future logique commune doit couvrir au minimum :
11. diagnostics explicites si outil, target, AAR, NDK ou output manque ;
12. absence de secret de signature dans le dépôt.
Le projet Android natif doit acquérir un Gradle Wrapper épinglé à la version compatible AGP afin que `CMD-051` devienne réellement reproductible sans dépendre d'un Gradle global.
Le projet Android natif déclare `minimumGradleVersion=9.6.0` et refuse au chargement une version inférieure. Le Gradle réellement utilisé est celui de l'environnement ; une version plus récente que le minimum est autorisée. Le projet n'épingle pas de wrapper natif.
## ABI et compatibilité OS
@@ -134,15 +144,15 @@ Aucune réécriture Gradle productive dans cette tranche.
### `0-pre.2` — ownership Gradle/Cargo sur Snake mono-ABI
Introduire le Gradle Wrapper compatible AGP 9.4 et la logique Gradle commune minimale. Faire de `:game-snake-poc:assembleDebug` le propriétaire du build Rust `arm64-v8a`, de l'extraction/linkage SDL3 et des `jniLibs` générés, sans appel préalable au script Python.
Introduire la logique Gradle commune minimale et prouver que `:game-snake-poc:assembleDebug` possède le build Rust `arm64-v8a`, l'extraction/linkage SDL3 et les `jniLibs` générés, sans appel préalable au script Python. Cette preuve a initialement utilisé un wrapper Gradle 9.6.0 afin d'isoler le task wiring.
Le delta doit rester borné à une ABI pour valider l'ordre des tâches, les inputs/outputs, le mapping de feature et les diagnostics avant de multiplier les dimensions.
La gate utilisateur du 2026-09-21 a validé ce chemin. Après cette preuve, la politique toolchain a été révisée : le projet Android natif utilise désormais un Gradle système `>= 9.6.0` et le JDK courant de l'environnement au lieu d'épinger Gradle/JDK pour ce chemin.
### `0-pre.3` — multi-ABI et APK universal
### `0-pre.3` — toolchain minimale, multi-ABI et APK universal
Étendre la logique commune à `arm64-v8a + x86_64`, produire un APK Debug universal Snake et vérifier mécaniquement les deux couples `libSDL3.so`/`libgame_android_entrypoint.so`.
Retirer le wrapper natif introduit pour la preuve `0-pre.2`, déclarer et contrôler `Gradle >= 9.6.0`, ne plus imposer `JAVA_HOME`, puis étendre la logique commune à `arm64-v8a + x86_64`. Produire un APK Debug universal Snake et vérifier mécaniquement les deux couples `libSDL3.so`/`libgame_android_entrypoint.so`.
Ajouter Reflex comme second consommateur dans cette tranche si, et seulement si, la factorisation commune réduit son activation à une configuration de module sans nouvelle architecture.
La factorisation commune étant réduite au mapping `module -> feature`, ajouter Reflex comme second consommateur avec les mêmes deux ABI, sans nouvelle architecture.
### `0-pre.4` — AAB, minSdk et fermeture du chemin historique
@@ -185,12 +195,11 @@ adb version
adb devices -l
emulator -list-avds
(cd Android && gradle --version)
printf 'configured NDK: '; sed -n 's/^androidNdkVersion=//p' Android/gradle.properties
ls -ld "$ANDROID_HOME/ndk/28.2.13676358"
printf 'configured NDK: '; sed -n 's/^androidNdkVersion=//p' ls -ld "$ANDROID_HOME/ndk/28.2.13676358"
test -f Android/libs/SDL3-3.4.16.aar && sha256sum Android/libs/SDL3-3.4.16.aar
```
L'absence du Gradle global n'est pas destinée à devenir une dépendance durable : `0-pre.2` doit introduire le wrapper. En revanche, l'inventaire demandé par le prompt `004` doit relever l'état actuel avant cette transition.
La politique a été révisée après validation de `0-pre.2` : le projet Android natif dépend volontairement d'un Gradle fourni par l'environnement, avec minimum `9.6.0` déclaré et contrôlé par `settings.gradle`. Il n'impose plus de wrapper ni de `JAVA_HOME`; les gates consignent les versions réellement utilisées.
## Critères d'entrée en RC

View File

@@ -1,5 +1,5 @@
<!-- file: docs/rules/RULES_COMMANDS.md -->
<!-- version: 14 -->
<!-- version: 15 -->
# Règles d'exécution des commandes
@@ -48,11 +48,11 @@
## Android et Gradle
- **CMD-ANDROID-001** — Les commandes Gradle Android sont exécutées depuis `Android/` ou avec un chemin explicite vers le wrapper du projet.
- **CMD-ANDROID-002** — Les tâches ciblées par application sont préférées, par exemple `./gradlew :game-reflex-poc:assembleDebug`, lorsqu'elles existent.
- **CMD-ANDROID-001** — Les commandes Gradle du projet Android natif sont exécutées depuis `Android/` avec le `gradle` résolu par lenvironnement ; sa version doit être au moins égale à `minimumGradleVersion` déclaré par le projet.
- **CMD-ANDROID-002** — Les tâches ciblées par application sont préférées, par exemple `gradle :game-reflex-poc:assembleDebug`, lorsqu'elles existent.
- **CMD-ANDROID-003** — Un build Android global n'est pas exécuté si la tranche ne touche ni Android ni le contrat natif utilisé par Android.
- **CMD-ANDROID-004** — `gradle clean` ou `./gradlew clean` reste un nettoyage Android ciblé ; il n'est pas rendu obligatoire uniquement parce qu'un `cargo clean` est planifié.
- **CMD-ANDROID-005** — Les commandes Android réelles ne deviennent des gates qu'après introduction du wrapper Gradle, de l'AGP, du NDK, de SDL3 et des modules exécutables correspondants.
- **CMD-ANDROID-004** — `gradle clean` reste un nettoyage Android ciblé ; il n'est pas rendu obligatoire uniquement parce qu'un `cargo clean` est planifié.
- **CMD-ANDROID-005** — Les commandes Android réelles ne deviennent des gates qu'après déclaration d'un minimum Gradle contrôlé, de l'AGP, du NDK, de SDL3 et des modules exécutables correspondants.
## Web

View File

@@ -1,5 +1,5 @@
<!-- file: docs/rules/RULES_VALIDATION_MATRIX.md -->
<!-- version: 5 -->
<!-- version: 6 -->
# Matrice normative des commandes et validations
@@ -38,7 +38,7 @@ Les commandes ciblées restent la norme pendant l'implémentation ; les gates wo
| `CMD-046` | `(cd <tauri-app> && cargo tauri android dev)` | gates Rust/frontend applicables | smoke interactif Tauri Android | `pre`/beta |
| `CMD-047` | `(cd <tauri-app> && cargo tauri android build)` | gates Rust/frontend applicables | packaging Tauri Android final/prefinal | beta/RC |
| `CMD-050` | build Rust Android ABI ciblé | gates Rust applicables | Android/JNI/backend natif touché | pre/beta |
| `CMD-051` | `(cd Android && ./gradlew :<app>:assembleDebug)` | `CMD-050` si Rust natif change | Android/app/manifest/Java touché | pre/beta |
| `CMD-051` | `(cd Android && gradle :<app>:assembleDebug)` | `CMD-050` si Rust natif change | Android/app/manifest/Java touché | pre/beta |
| `CMD-052` | install + smoke AVD | `CMD-051` | Android concerné | beta |
| `CMD-053` | install + smoke appareil réel | `CMD-051` | Android concerné | beta/RC |
| `CMD-060` | `cargo clean --dry-run --verbose` | — | contrôle disque / préparation nettoyage | maintenance |