220 lines
9.0 KiB
JavaScript
220 lines
9.0 KiB
JavaScript
// 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();
|