0.3.1-0-pre.2.fix.2
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<!-- file: crates/apps/game-snake-poc-tauri/README.md -->
|
||||
<!-- version: 2 -->
|
||||
<!-- version: 3 -->
|
||||
|
||||
# game-snake-poc-tauri
|
||||
|
||||
@@ -22,6 +22,6 @@ Le frontend minimal de `0.3.1-0-pre.2` valide uniquement le démarrage Tauri, le
|
||||
|
||||
Les hooks `beforeDevCommand` et `beforeBuildCommand` de Tauri possèdent le build WASM et Vite. Aucun orchestrateur Python n'est utilisé. Les bindings WASM, la distribution Vite, les caches, `node_modules/` et le projet Android généré restent hors des sources livrées ou dans des chemins générés ignorés.
|
||||
|
||||
Pour Tauri CLI `2.11.x`, le projet Android généré utilise encore Gradle `8.14.3`. Le hook `scripts/prepare-android-gradle.mjs` applique avant `dev`/`build` la migration Android déjà retenue upstream par Tauri (`Gradle 9.6.1`, AGP `9.3.1`, Kotlin `2.2.10`) afin de rester exécutable avec Java 25. Cette préparation modifie uniquement `gen/android/`, reste idempotente et ne dépend pas du Gradle global installé sur la machine.
|
||||
Le host ne modifie pas le projet Android généré par Tauri. La branche stable Tauri 2.11.x conserve son propre wrapper Gradle ; les commandes Android doivent donc s'exécuter avec un JDK compatible avec cette chaîne. Pour la machine de validation, `JAVA_HOME` doit pointer vers le JBR fourni par Android Studio (ou vers un autre JDK compatible), plutôt que vers le Java 25 global.
|
||||
|
||||
Voir [`USAGE.md`](USAGE.md) pour l'initialisation locale et les smokes Android.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: crates/apps/game-snake-poc-tauri/USAGE.md -->
|
||||
<!-- version: 2 -->
|
||||
<!-- version: 3 -->
|
||||
|
||||
# Utilisation — Snake Tauri Android
|
||||
|
||||
@@ -9,7 +9,16 @@ Le host utilise Cargo/Rust, `cargo tauri`, Node/npm, `wasm-bindgen`, Java et le
|
||||
|
||||
`NDK_HOME` n'est pas un prérequis utilisateur du projet. Tauri sélectionne la version NDK side-by-side appropriée sous `$ANDROID_HOME/ndk/<version>` et peut injecter lui-même `NDK_HOME` dans ses sous-processus Android. Une variable globale ne doit donc pas être ajoutée uniquement pour satisfaire la documentation générique de Tauri.
|
||||
|
||||
`JAVA_HOME` n'est pas imposé tant que la CLI Tauri résout correctement `java` depuis l'environnement. L'environnement de validation utilise Java 25 ; Tauri CLI `2.11.x` génère encore un wrapper Gradle `8.14.3`, qui ne peut pas exécuter ce JDK. Le host corrige ce scaffold généré avant les hooks frontend vers Gradle `9.6.1`, AGP `9.3.1` et Kotlin `2.2.10`, combinaison déjà adoptée par la migration Android upstream de Tauri. Le Gradle global installé sur la machine n'est pas utilisé par `gradlew` et n'est pas requis par ce correctif.
|
||||
Pour Android, `JAVA_HOME` doit pointer vers un JDK compatible avec la chaîne Gradle générée par la version stable de Tauri 2 utilisée par le projet. La documentation Tauri recommande le JBR fourni par Android Studio. Le Java 25 global de la machine de validation n'est pas utilisé pour les commandes Tauri Android tant qu'il reste incompatible avec le wrapper Gradle stable. Le Gradle global installé sur la machine n'est pas utilisé par `gradlew` et n'est pas un prérequis du projet.
|
||||
|
||||
Exemple lorsque Android Studio est installé sous `/opt/android-studio` :
|
||||
|
||||
```bash
|
||||
export JAVA_HOME=/opt/android-studio/jbr
|
||||
"$JAVA_HOME/bin/java" -version
|
||||
```
|
||||
|
||||
Si Android Studio se trouve ailleurs, utiliser le chemin réel de son répertoire `jbr`. Ne pas modifier `gen/android` pour contourner une incompatibilité de JDK.
|
||||
|
||||
Pour les cibles actuellement disponibles, `aarch64-linux-android` permet le smoke sur l'appareil ARM64 et `x86_64-linux-android` celui des AVD x86_64. Les autres ABI ne sont pas requises pour `0-pre.2`.
|
||||
|
||||
@@ -27,7 +36,7 @@ Initialiser une fois le projet Android généré par Tauri :
|
||||
(cd crates/apps/game-snake-poc-tauri && cargo tauri android init)
|
||||
```
|
||||
|
||||
Le répertoire `gen/` produit par Tauri est généré et ignoré ; il n'appartient pas aux deltas. Le correctif Gradle 9 est appliqué à ce répertoire par le hook Tauri au prochain `android dev` ou `android build`, y compris si `gen/android` existe déjà depuis `0-pre.2`. Il n'est donc pas nécessaire de rejouer `android init` pour appliquer le fix.
|
||||
Le répertoire `gen/` produit par Tauri est généré et ignoré ; il n'appartient pas aux deltas et ne doit pas être patché par des scripts propres au jeu. Une initialisation déjà réalisée reste utilisable ; il n'est pas nécessaire de rejouer `android init` pour ce fix.
|
||||
|
||||
## Smoke Android de développement
|
||||
|
||||
|
||||
@@ -1,42 +1,9 @@
|
||||
// file: crates/apps/game-snake-poc-tauri/build.rs
|
||||
// version: 2
|
||||
// version: 3
|
||||
|
||||
//! Build-time integration for the Snake Tauri host.
|
||||
|
||||
const GENERATED_ANDROID_TAURI_BUILD_GRADLE: &str = "gen/android/app/tauri.build.gradle.kts";
|
||||
const GRADLE_8_IMPLEMENTATION_DECLARATION: &str = "val implementation by configurations";
|
||||
const GRADLE_9_IMPLEMENTATION_DECLARATION: &str = "val implementation = configurations.getByName(\"implementation\")";
|
||||
|
||||
fn patch_generated_android_gradle() {
|
||||
let manifest_dir = match std::env::var_os("CARGO_MANIFEST_DIR") {
|
||||
Some(value) => std::path::PathBuf::from(value),
|
||||
None => return,
|
||||
};
|
||||
let path = manifest_dir.join(GENERATED_ANDROID_TAURI_BUILD_GRADLE);
|
||||
let content = match std::fs::read_to_string(&path) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) if error.kind() == std::io::ErrorKind::NotFound => return,
|
||||
std::result::Result::Err(error) => {
|
||||
println!("cargo:warning=failed to inspect {}: {error}", path.display());
|
||||
return;
|
||||
},
|
||||
};
|
||||
if content.contains(GRADLE_9_IMPLEMENTATION_DECLARATION) {
|
||||
return;
|
||||
}
|
||||
if !content.contains(GRADLE_8_IMPLEMENTATION_DECLARATION) {
|
||||
println!("cargo:warning={} does not match the expected Tauri 2.11.x Gradle bridge", path.display());
|
||||
return;
|
||||
}
|
||||
let patched = content.replace(GRADLE_8_IMPLEMENTATION_DECLARATION, GRADLE_9_IMPLEMENTATION_DECLARATION);
|
||||
if let std::result::Result::Err(error) = std::fs::write(&path, patched) {
|
||||
println!("cargo:warning=failed to prepare {} for Gradle 9: {error}", path.display());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
tauri_build::build();
|
||||
patch_generated_android_gradle();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -6,9 +6,8 @@
|
||||
"scripts": {
|
||||
"wasm:dev": "cargo build -p game-snake-poc-wasm --target wasm32-unknown-unknown && wasm-bindgen ../../../../builds/sasedev-games/target/wasm32-unknown-unknown/debug/game_snake_poc_wasm.wasm --target web --out-dir ../../../../builds/sasedev-games/game-snake-poc-tauri/wasm --out-name game_snake_poc_wasm",
|
||||
"wasm:build": "cargo build -p game-snake-poc-wasm --release --target wasm32-unknown-unknown && wasm-bindgen ../../../../builds/sasedev-games/target/wasm32-unknown-unknown/release/game_snake_poc_wasm.wasm --target web --out-dir ../../../../builds/sasedev-games/game-snake-poc-tauri/wasm --out-name game_snake_poc_wasm",
|
||||
"dev": "npm run android:prepare && npm run wasm:dev && vite",
|
||||
"build": "npm run android:prepare && npm run wasm:build && tsc && vite build",
|
||||
"android:prepare": "node scripts/prepare-android-gradle.mjs"
|
||||
"dev": "npm run wasm:dev && vite",
|
||||
"build": "npm run wasm:build && tsc && vite build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fltsci/tauri-plugin-tracing": "^0.3",
|
||||
|
||||
@@ -1,219 +0,0 @@
|
||||
// file: crates/apps/game-snake-poc-tauri/scripts/prepare-android-gradle.mjs
|
||||
// version: 1
|
||||
|
||||
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
||||
import { resolve } from "node:path";
|
||||
import process from "node:process";
|
||||
|
||||
const GRADLE_VERSION = "9.6.1";
|
||||
const AGP_VERSION = "9.3.1";
|
||||
const KOTLIN_VERSION = "2.2.10";
|
||||
|
||||
function fail(message) {
|
||||
process.stderr.write(`Snake Tauri Android Gradle preparation failed: ${message}\n`);
|
||||
process.exitCode = 1;
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
function replaceRequired(content, previous, next, label) {
|
||||
if (content.includes(next)) {
|
||||
return content;
|
||||
}
|
||||
if (!content.includes(previous)) {
|
||||
return fail(`${label}: expected neither the Tauri 2.11.x form nor the prepared form`);
|
||||
}
|
||||
return content.replace(previous, next);
|
||||
}
|
||||
|
||||
function removeLine(content, line) {
|
||||
const withLf = `${line}\n`;
|
||||
if (content.includes(withLf)) {
|
||||
return content.replace(withLf, "");
|
||||
}
|
||||
if (content.endsWith(line)) {
|
||||
return content.slice(0, -line.length);
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
function appendProperty(content, property) {
|
||||
if (content.includes(`${property}\n`) || content.endsWith(property)) {
|
||||
return content;
|
||||
}
|
||||
const separator = content.endsWith("\n") ? "" : "\n";
|
||||
return `${content}${separator}${property}\n`;
|
||||
}
|
||||
|
||||
function updateFile(path, transform) {
|
||||
if (!existsSync(path)) {
|
||||
return fail(`missing generated Android file: ${path}`);
|
||||
}
|
||||
const before = readFileSync(path, "utf8");
|
||||
const after = transform(before);
|
||||
if (after !== before) {
|
||||
writeFileSync(path, after, "utf8");
|
||||
}
|
||||
}
|
||||
|
||||
function patchWrapper(androidRoot) {
|
||||
const path = resolve(androidRoot, "gradle/wrapper/gradle-wrapper.properties");
|
||||
updateFile(path, content => replaceRequired(
|
||||
content,
|
||||
"gradle-8.14.3-bin.zip",
|
||||
`gradle-${GRADLE_VERSION}-bin.zip`,
|
||||
"Gradle wrapper",
|
||||
));
|
||||
}
|
||||
|
||||
function patchRootBuild(androidRoot) {
|
||||
const path = resolve(androidRoot, "build.gradle.kts");
|
||||
updateFile(path, content => {
|
||||
let result = replaceRequired(
|
||||
content,
|
||||
'classpath("com.android.tools.build:gradle:8.11.0")',
|
||||
`classpath("com.android.tools.build:gradle:${AGP_VERSION}")`,
|
||||
"Android Gradle Plugin",
|
||||
);
|
||||
result = replaceRequired(
|
||||
result,
|
||||
'classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25")',
|
||||
`classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${KOTLIN_VERSION}")`,
|
||||
"Kotlin Gradle Plugin",
|
||||
);
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
function patchBuildSrcManifest(androidRoot) {
|
||||
const path = resolve(androidRoot, "buildSrc/build.gradle.kts");
|
||||
updateFile(path, content => replaceRequired(
|
||||
content,
|
||||
'implementation("com.android.tools.build:gradle:8.11.0")',
|
||||
`implementation("com.android.tools.build:gradle:${AGP_VERSION}")`,
|
||||
"buildSrc Android Gradle Plugin",
|
||||
));
|
||||
}
|
||||
|
||||
function patchBuildTask(androidRoot) {
|
||||
const path = resolve(androidRoot, "buildSrc/src/main/kotlin/BuildTask.kt");
|
||||
updateFile(path, content => {
|
||||
let result = content;
|
||||
if (!result.includes("import javax.inject.Inject")) {
|
||||
result = replaceRequired(
|
||||
result,
|
||||
"import org.gradle.api.tasks.TaskAction\n",
|
||||
"import org.gradle.api.tasks.TaskAction\nimport javax.inject.Inject\nimport org.gradle.process.ExecOperations\n",
|
||||
"BuildTask imports",
|
||||
);
|
||||
}
|
||||
result = replaceRequired(
|
||||
result,
|
||||
"open class BuildTask : DefaultTask() {\n @Input\n var rootDirRel: String? = null\n",
|
||||
"abstract class BuildTask : DefaultTask() {\n @get:Inject\n abstract val execOperations: ExecOperations\n\n @Input\n var rootDirRel: String? = null\n @Input\n var projectDir: String? = null\n",
|
||||
"BuildTask ExecOperations declaration",
|
||||
);
|
||||
result = replaceRequired(
|
||||
result,
|
||||
" project.exec {\n workingDir(File(project.projectDir, rootDirRel))\n",
|
||||
" execOperations.exec {\n workingDir(File(projectDir, rootDirRel))\n",
|
||||
"BuildTask process execution",
|
||||
);
|
||||
result = result.replaceAll("project.logger.isEnabled", "logger.isEnabled");
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
function patchRustPlugin(androidRoot) {
|
||||
const path = resolve(androidRoot, "buildSrc/src/main/kotlin/RustPlugin.kt");
|
||||
updateFile(path, content => {
|
||||
let result = replaceRequired(
|
||||
content,
|
||||
" val targetBuildTask = project.tasks.maybeCreate(\n \"rustBuild$targetArchCapitalized$profileCapitalized\",\n BuildTask::class.java\n ).apply {\n",
|
||||
" val targetBuildTask = project.tasks.register(\n \"rustBuild$targetArchCapitalized$profileCapitalized\",\n BuildTask::class.java\n ) {\n",
|
||||
"RustPlugin task registration",
|
||||
);
|
||||
if (!result.includes(" projectDir = project.projectDir.path\n")) {
|
||||
result = replaceRequired(
|
||||
result,
|
||||
" rootDirRel = config.rootDirRel\n target = targetName\n",
|
||||
" rootDirRel = config.rootDirRel\n projectDir = project.projectDir.path\n target = targetName\n",
|
||||
"RustPlugin project directory",
|
||||
);
|
||||
}
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
function patchAppBuild(androidRoot) {
|
||||
const path = resolve(androidRoot, "app/build.gradle.kts");
|
||||
updateFile(path, content => {
|
||||
let result = content;
|
||||
if (!result.includes("import org.jetbrains.kotlin.gradle.dsl.JvmTarget")) {
|
||||
result = `import org.jetbrains.kotlin.gradle.dsl.JvmTarget\n${result}`;
|
||||
}
|
||||
result = replaceRequired(
|
||||
result,
|
||||
" isMinifyEnabled = true\n proguardFiles(\n *fileTree(\".\") { include(\"**/*.pro\") }\n .plus(getDefaultProguardFile(\"proguard-android-optimize.txt\"))\n .toList().toTypedArray()\n )\n",
|
||||
" optimization {\n enable = true\n }\n proguardFiles(\n *fileTree(\".\") {\n include(\"**/*.pro\")\n exclude(\"build/**\")\n }.files.toTypedArray()\n )\n",
|
||||
"Android release optimization DSL",
|
||||
);
|
||||
result = replaceRequired(
|
||||
result,
|
||||
" kotlinOptions {\n jvmTarget = \"1.8\"\n }\n buildFeatures {\n",
|
||||
" compileOptions {\n sourceCompatibility = JavaVersion.VERSION_1_8\n targetCompatibility = JavaVersion.VERSION_1_8\n }\n buildFeatures {\n",
|
||||
"Android compile options",
|
||||
);
|
||||
if (!result.includes("kotlin {\n compilerOptions")) {
|
||||
result = replaceRequired(
|
||||
result,
|
||||
"}\n\nrust {\n",
|
||||
"}\n\nkotlin {\n compilerOptions {\n jvmTarget = JvmTarget.JVM_1_8\n }\n}\n\nrust {\n",
|
||||
"Kotlin compiler options",
|
||||
);
|
||||
}
|
||||
result = result.replace('apply(from = "tauri.build.gradle.kts")', 'apply(from = file("tauri.build.gradle.kts"))');
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
function patchGradleProperties(androidRoot) {
|
||||
const path = resolve(androidRoot, "gradle.properties");
|
||||
updateFile(path, content => {
|
||||
let result = content;
|
||||
result = removeLine(result, "android.useAndroidX=true");
|
||||
result = removeLine(result, "android.nonTransitiveRClass=true");
|
||||
result = removeLine(result, "android.nonFinalResIds=false");
|
||||
result = appendProperty(result, "org.gradle.configuration-cache=true");
|
||||
result = appendProperty(result, "android.proguard.failOnMissingFiles=false");
|
||||
result = appendProperty(result, "android.builtInKotlin=false");
|
||||
result = appendProperty(result, "android.newDsl=false");
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
function resolveAndroidRoot() {
|
||||
const marker = "--android-project";
|
||||
const markerIndex = process.argv.indexOf(marker);
|
||||
if (markerIndex >= 0) {
|
||||
const value = process.argv[markerIndex + 1];
|
||||
if (value === undefined || value.startsWith("--")) {
|
||||
return fail(`${marker} requires a path`);
|
||||
}
|
||||
return resolve(process.cwd(), value);
|
||||
}
|
||||
return resolve(process.cwd(), "gen/android");
|
||||
}
|
||||
|
||||
function main() {
|
||||
const androidRoot = resolveAndroidRoot();
|
||||
patchWrapper(androidRoot);
|
||||
patchRootBuild(androidRoot);
|
||||
patchBuildSrcManifest(androidRoot);
|
||||
patchBuildTask(androidRoot);
|
||||
patchRustPlugin(androidRoot);
|
||||
patchAppBuild(androidRoot);
|
||||
patchGradleProperties(androidRoot);
|
||||
process.stdout.write(`Prepared Tauri Android Gradle ${GRADLE_VERSION} / AGP ${AGP_VERSION} / Kotlin ${KOTLIN_VERSION}.\n`);
|
||||
}
|
||||
|
||||
main();
|
||||
Reference in New Issue
Block a user