|
1 | 1 | import org.jetbrains.kotlin.gradle.dsl.JvmTarget |
2 | 2 | import java.util.Properties |
| 3 | +import java.util.zip.ZipEntry |
| 4 | +import java.util.zip.ZipFile |
| 5 | +import java.util.zip.ZipOutputStream |
3 | 6 |
|
4 | 7 | plugins { |
5 | 8 | alias(libs.plugins.android.application) |
@@ -65,6 +68,13 @@ android { |
65 | 68 | } |
66 | 69 |
|
67 | 70 | packaging { |
| 71 | + resources { |
| 72 | + // Coroutine debug probes are useful only to a debugger and should |
| 73 | + // not be packaged in production or debug APKs. |
| 74 | + excludes += "DebugProbesKt.bin" |
| 75 | + excludes += "META-INF/**" |
| 76 | + excludes += "/META-INF/**" |
| 77 | + } |
68 | 78 | jniLibs { |
69 | 79 | useLegacyPackaging = true |
70 | 80 | } |
@@ -158,6 +168,57 @@ tasks.configureEach { |
158 | 168 | } |
159 | 169 | } |
160 | 170 |
|
| 171 | +val stripDebugApkMetadata by tasks.registering { |
| 172 | + dependsOn("packageDebug") |
| 173 | + |
| 174 | + doLast { |
| 175 | + val outputDir = layout.buildDirectory.dir("outputs/apk/debug").get().asFile |
| 176 | + val debugKeystore = file("${System.getProperty("user.home")}/.android/debug.keystore") |
| 177 | + check(debugKeystore.isFile) { "Debug keystore was not found: $debugKeystore" } |
| 178 | + |
| 179 | + val buildToolsDir = android.sdkDirectory.resolve("build-tools/${android.buildToolsVersion}") |
| 180 | + val zipalign = buildToolsDir.resolve("zipalign.exe") |
| 181 | + val apksigner = buildToolsDir.resolve("apksigner.bat") |
| 182 | + check(zipalign.isFile && apksigner.isFile) { "Android build-tools are incomplete in $buildToolsDir" } |
| 183 | + |
| 184 | + outputDir.listFiles { file -> file.extension == "apk" }?.forEach { apk -> |
| 185 | + val unaligned = apk.resolveSibling("${apk.nameWithoutExtension}-stripped-unaligned.apk") |
| 186 | + val aligned = apk.resolveSibling("${apk.nameWithoutExtension}-stripped-aligned.apk") |
| 187 | + ZipFile(apk).use { input -> |
| 188 | + ZipOutputStream(unaligned.outputStream().buffered()).use { output -> |
| 189 | + val entries = input.entries() |
| 190 | + while (entries.hasMoreElements()) { |
| 191 | + val entry = entries.nextElement() |
| 192 | + if (entry.name == "DebugProbesKt.bin" || entry.name.startsWith("META-INF/")) continue |
| 193 | + output.putNextEntry(ZipEntry(entry.name).apply { time = entry.time }) |
| 194 | + if (!entry.isDirectory) input.getInputStream(entry).use { it.copyTo(output) } |
| 195 | + output.closeEntry() |
| 196 | + } |
| 197 | + } |
| 198 | + } |
| 199 | + exec { commandLine(zipalign.absolutePath, "-f", "4", unaligned.absolutePath, aligned.absolutePath) } |
| 200 | + exec { |
| 201 | + commandLine( |
| 202 | + apksigner.absolutePath, |
| 203 | + "sign", |
| 204 | + "--ks", debugKeystore.absolutePath, |
| 205 | + "--ks-pass", "pass:android", |
| 206 | + "--key-pass", "pass:android", |
| 207 | + "--v1-signing-enabled", "false", |
| 208 | + "--out", apk.absolutePath, |
| 209 | + aligned.absolutePath, |
| 210 | + ) |
| 211 | + } |
| 212 | + unaligned.delete() |
| 213 | + aligned.delete() |
| 214 | + } |
| 215 | + } |
| 216 | +} |
| 217 | + |
| 218 | +tasks.matching { it.name == "assembleDebug" }.configureEach { |
| 219 | + finalizedBy(stripDebugApkMetadata) |
| 220 | +} |
| 221 | + |
161 | 222 | kotlin { |
162 | 223 | compilerOptions { |
163 | 224 | jvmTarget.set(JvmTarget.JVM_21) |
|
0 commit comments