0.3.1-0-pre.2.fix.1

This commit is contained in:
2026-09-20 21:38:21 +02:00
parent 51371c1b24
commit bded27c944
12 changed files with 569 additions and 22 deletions

View File

@@ -0,0 +1,219 @@
// 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();