import org.gradle.api.GradleException allprojects { repositories { google() mavenCentral() } } fun installArtifact( root: File, group: String, name: String, version: String, ext: String, src: File, ) { val dir = root.resolve("${group.replace('.', '/')}/$name/$version") dir.mkdirs() src.copyTo(dir.resolve("$name-$version.$ext"), overwrite = true) } fun googleMavenBases(group: String): List = if (group.startsWith("com.android") || group.startsWith("androidx") || group.startsWith("com.google.android")) { listOf( "https://dl.google.com/dl/android/maven2", "https://dl.google.com/android/maven2", "https://maven.google.com", ) } else { listOf( "https://repo.maven.apache.org/maven2", "https://dl.google.com/dl/android/maven2", "https://maven.google.com", ) } fun downloadUrl(url: String, dest: File) { dest.parentFile.mkdirs() exec { commandLine("curl", "-fsSL", url, "-o", dest.absolutePath) } } fun ensurePom(root: File, group: String, name: String, version: String) { val dir = root.resolve("${group.replace('.', '/')}/$name/$version") dir.mkdirs() val pom = dir.resolve("$name-$version.pom") if (pom.exists() && pom.length() > 0L) { return } val groupPath = group.replace('.', '/') for (base in googleMavenBases(group)) { val url = "$base/$groupPath/$name/$version/$name-$version.pom" try { downloadUrl(url, pom) if (pom.exists() && pom.length() > 0L) { return } } catch (_: Exception) { pom.delete() } } throw GradleException("POM not found: $group:$name:$version") } fun exportConfiguration(projectPath: String, configName: String, offlineRoot: File): Int { val target = project(projectPath) val configuration = target.configurations.getByName(configName) configuration.resolve() val modules = linkedSetOf>() configuration.resolvedConfiguration.resolvedArtifacts.forEach { artifact -> val id = artifact.moduleVersion.id modules.add(Triple(id.group, id.name, id.version)) installArtifact( offlineRoot, id.group, id.name, id.version, artifact.extension ?: "jar", artifact.file, ) } modules.forEach { (group, name, version) -> ensurePom(offlineRoot, group, name, version) } println("Exported ${modules.size} modules from ${projectPath}:${configName}") return modules.size } fun exportAndroidRuntimeClasspath(offlineRoot: File): Int = exportConfiguration(":app", "releaseRuntimeClasspath", offlineRoot) val agpVersion: String = providers.gradleProperty("agpVersion").orElse("8.11.0").get() tasks.register("exportOfflineMaven") { dependsOn(":tools:compileJava") doLast { val offlineRoot = file("${rootProject.projectDir}/../offline-maven").apply { mkdirs() } val modules = exportConfiguration(":tools", "agp", offlineRoot) file("${offlineRoot.absolutePath}/.agp-offline-complete").writeText( "agpVersion=$agpVersion\nmodules=$modules\n", ) } } tasks.register("exportAllOfflineMaven") { dependsOn(":tools:compileJava", ":app:preBuild") doLast { val offlineRoot = file("${rootProject.projectDir}/../offline-maven").apply { mkdirs() } var modules = 0 modules += exportConfiguration(":tools", "agp", offlineRoot) modules += exportConfiguration(":tools", "buildPlugins", offlineRoot) modules += exportAndroidRuntimeClasspath(offlineRoot) file("${offlineRoot.absolutePath}/.agp-offline-complete").writeText( "agpVersion=$agpVersion\nmodules=$modules\n", ) file("${offlineRoot.absolutePath}/.android-deps-offline-complete").writeText( "modules=$modules\n", ) println("Exported ${modules} total modules to ${offlineRoot.absolutePath}") } }