import com.android.build.api.artifact.SingleArtifact import com.android.build.api.variant.BuiltArtifactsLoader import java.nio.file.Files import java.nio.file.StandardCopyOption import java.time.LocalDateTime import java.time.format.DateTimeFormatter import javax.xml.parsers.DocumentBuilderFactory plugins { alias(libs.plugins.android.application) alias(libs.plugins.google.gms.google.services) } fun readStringResource(projectDir: File, resName: String): String { val xml = File(projectDir, "src/main/res/values/strings.xml") if (!xml.exists()) return "app" val doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(xml) val nodes = doc.getElementsByTagName("string") for (i in 0 until nodes.length) { val n = nodes.item(i) val nameAttr = n.attributes?.getNamedItem("name")?.nodeValue if (nameAttr == resName) { return n.textContent.trim() } } return "app" } android { namespace = "com.amz.genie" compileSdk = 36 defaultConfig { applicationId = "com.amz.genie" minSdk = 26 targetSdk = 36 versionCode = 57 versionName = "0.5.7" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" vectorDrawables.useSupportLibrary = true } buildTypes { release { isMinifyEnabled = false proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) } } compileOptions { sourceCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11 } } /** * Task: copy APK artifact -> output folder, rename with timestamp */ abstract class CopyRenameApkTask : DefaultTask() { @get:InputDirectory @get:PathSensitive(PathSensitivity.RELATIVE) abstract val inputApkFolder: DirectoryProperty @get:OutputDirectory abstract val outputDir: DirectoryProperty @get:Internal abstract val builtArtifactsLoader: Property @get:Input abstract val appName: Property @TaskAction fun run() { val outDirFile = outputDir.get().asFile outDirFile.deleteRecursively() outDirFile.mkdirs() val builtArtifacts = builtArtifactsLoader.get().load(inputApkFolder.get()) ?: error("Cannot load APK artifacts from ${inputApkFolder.get().asFile}") val ts = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd-HHmmss")) val prefix = appName.get() builtArtifacts.elements.forEach { artifact -> val src = File(artifact.outputFile) // Kalau ada splits, bisa lebih dari 1 apk. Kita bedakan pakai versionCode/variantName optional. val name = buildString { append(prefix).append("-").append(ts) artifact.versionCode?.let { append("-").append(it) } append(".apk") } val dst = File(outDirFile, name) Files.copy(src.toPath(), dst.toPath(), StandardCopyOption.REPLACE_EXISTING) } } } androidComponents { onVariants(selector().withBuildType("debug")) { variant -> val t = tasks.register("copyRename${variant.name.replaceFirstChar { it.uppercase() }}Apk", CopyRenameApkTask::class.java) { val label = readStringResource(project.projectDir, "app_name") appName.set(label) outputDir.set(layout.buildDirectory.dir(variant.name)) builtArtifactsLoader.set(variant.artifacts.getBuiltArtifactsLoader()) } // Listen ke artifact APK: task otomatis jalan saat APK dibuat (assembleDebug, dll) variant.artifacts .use(t) .wiredWith { it.inputApkFolder } .toListenTo(SingleArtifact.APK) } } dependencies { implementation(libs.androidx.core.ktx) implementation(libs.androidx.appcompat) implementation(libs.material) implementation(libs.androidx.activity) implementation(libs.androidx.constraintlayout) testImplementation(libs.junit) androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.espresso.core) implementation(libs.lottie) implementation(libs.sdp.android) implementation(libs.retrofit) implementation(libs.converter.gson) implementation(libs.okhttp) implementation(libs.logging.interceptor) implementation(libs.glide) implementation(libs.androidx.swiperefreshlayout) implementation(platform(libs.firebase.bom)) implementation(libs.firebase.analytics) implementation(libs.firebase.messaging) implementation(libs.firebase.auth) implementation(libs.androidx.emoji2) implementation(libs.androidx.emoji2.views.helper) implementation(libs.androidx.emoji2.emojipicker) }