buildscript { ext.kotlin_version = '1.9.22' repositories { google() mavenCentral() } dependencies { classpath 'com.android.tools.build:gradle:8.5.2' // START: FlutterFire Configuration classpath 'com.google.gms:google-services:4.4.1' // END: FlutterFire Configuration classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } allprojects { repositories { google() mavenCentral() } } rootProject.buildDir = '../build' subprojects { // Note: Do not override project.buildDir across different drives on Windows (H: vs C:) // Inject namespace into plugins that don't have it (required for AGP 8+) afterEvaluate { project -> if (project.hasProperty('android')) { project.android { if (namespace == null) { namespace project.group } } } } } subprojects { project.evaluationDependsOn(':app') } tasks.register("clean", Delete) { delete rootProject.buildDir } // Auto-wrap x86_64 AAPT2 on ARM64 Linux hosts (e.g. CI runner) to run seamlessly via QEMU gradle.taskGraph.whenReady { taskGraph -> String os = System.getProperty("os.name", "").toLowerCase() String arch = System.getProperty("os.arch", "").toLowerCase() if (os.contains("linux") && (arch.contains("aarch64") || arch.contains("arm64"))) { def qemu = new File("/usr/bin/qemu-x86_64-static").exists() ? "/usr/bin/qemu-x86_64-static" : "qemu-x86_64-static" def wrapAapt2 = { def searchDirs = [] def gh = gradle.gradleUserHomeDir if (gh != null && gh.exists()) { def transforms = new File(gh, "caches") if (transforms.exists()) searchDirs.add(transforms) } def sdk = new File("/opt/android-sdk-linux/build-tools") if (sdk.exists()) searchDirs.add(sdk) def rootGradle = new File("/root/.gradle/caches") if (rootGradle.exists()) searchDirs.add(rootGradle) searchDirs.each { dir -> dir.eachFileRecurse(groovy.io.FileType.FILES) { file -> if (file.name == "aapt2" && !file.name.endsWith(".orig")) { try { byte[] header = new byte[4] file.withInputStream { is -> is.read(header) } if (header[0] == 0x7F && header[1] == 0x45 && header[2] == 0x4C && header[3] == 0x46) { def orig = new File(file.parentFile, "aapt2.orig") if (!orig.exists()) { file.renameTo(orig) orig.setExecutable(true) } file.text = "#!/bin/sh\nexec ${qemu} -L /usr/x86_64-linux-gnu \"\$(dirname \"\$0\")/aapt2.orig\" \"\$@\"\n" file.setExecutable(true) println "[ARM64 CI] Wrapped AAPT2 at ${file.absolutePath} with QEMU" } } catch (Exception ignored) {} } } } } taskGraph.allTasks.findAll { it.name.contains("Resource") || it.name.contains("Aapt") || it.name.contains("Package") || it.name.contains("Bundle") }.each { task -> task.doFirst { wrapAapt2() } } } }