diff --git a/native/android/app/build.gradle.kts b/native/android/app/build.gradle.kts index cce8efd..226e9dd 100644 --- a/native/android/app/build.gradle.kts +++ b/native/android/app/build.gradle.kts @@ -1,3 +1,4 @@ +import java.io.File import java.util.Properties import java.util.zip.ZipEntry import java.util.zip.ZipFile @@ -23,8 +24,8 @@ android { applicationId = "com.matchlivetv.match_live_tv" minSdk = 24 targetSdk = 36 - versionCode = 30 - versionName = "2.0.9-native" + versionCode = 31 + versionName = "2.0.10-native" val apiBaseUrl = project.findProperty("API_BASE_URL") as String? ?: "https://www.matchlivetv.it" @@ -122,11 +123,21 @@ dependencies { androidTestImplementation("androidx.test.uiautomator:uiautomator:2.3.0") } -// Play Console: le .so prebuilt (AndroidX) sono già stripped → AGP non aggiunge -// BUNDLE-METADATA/com.android.tools.build.debugsymbols. Incorporiamo un zip ABI/.so -// nell'intermediary bundle prima della firma. +// Play Console: le .so prebuilt (AndroidX) sono già stripped → AGP salta l'estrazione +// (niente BUNDLE-METADATA/com.android.tools.build.debugsymbols). Generiamo i .so.sym +// come fa AGP (llvm-objcopy --strip-debug) e li iniettiamo nell'intermediary AAB. +fun findLlvmObjcopy(): File { + val ndkRoot = File(android.sdkDirectory, "ndk") + val ndkDirs = ndkRoot.listFiles()?.filter { it.isDirectory }?.sortedByDescending { it.name }.orEmpty() + for (ndk in ndkDirs) { + val candidate = ndk.resolve("toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-objcopy") + if (candidate.isFile) return candidate + } + error("llvm-objcopy non trovato sotto ${ndkRoot.absolutePath}") +} + val injectNativeDebugSymbolsInReleaseBundle by tasks.registering { - description = "Embed native-debug-symbols.zip into the release AAB intermediary" + description = "Embed native-debug-symbols.zip (.so.sym) into the release AAB intermediary" val mergeNative = tasks.named("mergeReleaseNativeLibs") val packageBundle = tasks.named("packageReleaseBundle") dependsOn(mergeNative, packageBundle) @@ -157,15 +168,40 @@ val injectNativeDebugSymbolsInReleaseBundle by tasks.registering { require(libsDir.isDirectory) { "Native libs missing: $libsDir" } require(aabFile.isFile) { "Intermediary AAB missing: $aabFile" } + val objcopy = findLlvmObjcopy() val workDir = layout.buildDirectory.dir("tmp/native-debug-symbols-inject").get().asFile workDir.deleteRecursively() workDir.mkdirs() + val symbolsRoot = workDir.resolve("symbols") + symbolsRoot.mkdirs() + + var count = 0 + libsDir.walkTopDown().filter { it.isFile && it.extension == "so" }.forEach { so -> + val rel = so.relativeTo(libsDir).invariantSeparatorsPath + val outRel = "$rel.sym" + val outFile = symbolsRoot.resolve(outRel) + outFile.parentFile.mkdirs() + // Allineato ad AGP SYMBOL_TABLE: llvm-objcopy --strip-debug → *.so.sym + val proc = ProcessBuilder( + objcopy.absolutePath, + "--strip-debug", + so.absolutePath, + outFile.absolutePath, + ).redirectErrorStream(true).start() + val out = proc.inputStream.bufferedReader().readText() + check(proc.waitFor() == 0) { + "objcopy failed for $rel: $out" + } + count++ + } + check(count > 0) { "Nessuna .so da cui generare simboli in $libsDir" } + val symbolsZip = workDir.resolve("native-debug-symbols.zip") ZipOutputStream(symbolsZip.outputStream().buffered()).use { zos -> - libsDir.walkTopDown().filter { it.isFile && it.extension == "so" }.forEach { so -> - val rel = so.relativeTo(libsDir).invariantSeparatorsPath + symbolsRoot.walkTopDown().filter { it.isFile }.forEach { f -> + val rel = f.relativeTo(symbolsRoot).invariantSeparatorsPath zos.putNextEntry(ZipEntry(rel)) - so.inputStream().use { it.copyTo(zos) } + f.inputStream().use { it.copyTo(zos) } zos.closeEntry() } } @@ -192,7 +228,9 @@ val injectNativeDebugSymbolsInReleaseBundle by tasks.registering { } } outAab.copyTo(aabFile, overwrite = true) - logger.lifecycle("Injected $metaPath (${symbolsZip.length()} bytes) into ${aabFile.name}") + logger.lifecycle( + "Injected $metaPath ($count .so.sym, ${symbolsZip.length()} bytes) into ${aabFile.name} via ${objcopy.name}", + ) } }