feat: use extractNativeLibs to reduce installed app size

While this increases the APK size, it also reduces the installed size due to libs not having to be extracted.
This commit is contained in:
rushiiMachine 2025-01-15 01:46:35 -08:00
parent ac33d65bcf
commit 3bbd1bebed
No known key found for this signature in database
GPG key ID: DCBE5952BB3B6420
3 changed files with 40 additions and 8 deletions

View file

@ -22,6 +22,7 @@
<application
android:name=".ManagerApplication"
android:extractNativeLibs="false"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:largeHeap="true"

View file

@ -6,14 +6,13 @@ import com.aliucord.manager.manager.PathManager
import com.aliucord.manager.patcher.StepRunner
import com.aliucord.manager.patcher.steps.StepGroup
import com.aliucord.manager.patcher.steps.base.Step
import com.aliucord.manager.patcher.steps.base.StepState
import com.aliucord.manager.patcher.steps.download.CopyDependenciesStep
import com.github.diamondminer88.zip.*
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
/**
* Align certain files in the APK to the respective boundaries.
* Align certain files in the APK to the necessary boundaries.
*/
class AlignmentStep : Step(), KoinComponent {
private val paths: PathManager by inject()
@ -24,12 +23,8 @@ class AlignmentStep : Step(), KoinComponent {
override suspend fun execute(container: StepRunner) {
val apk = container.getStep<CopyDependenciesStep>().patchedApk
if (Build.VERSION.SDK_INT < 29) {
state = StepState.Skipped
return
}
var resourcesArscBytes: ByteArray? = null
var nativeLibPaths: List<String>? = null
var dexCount: Int = -1
// Align resources.arsc due to targeting API 30 for silent install
@ -54,6 +49,18 @@ class AlignmentStep : Step(), KoinComponent {
}
}
// Align native libs due to using extractNativeLibs
nativeLibPaths = ZipReader(apk).use { zip ->
val libPaths = zip.entryNames.filter { it.endsWith(".so") }
for ((idx, path) in libPaths.withIndex()) {
// Index is just used as a placeholder id to cache on disk
val bytes = zip.openEntry(path)!!.read()
val file = paths.patchingWorkingDir().resolve("$idx.so")
file.writeBytes(bytes)
}
libPaths
}
ZipWriter(apk, /* append = */ true).use { zip ->
// Delete all the unaligned files from APK
if (resourcesArscBytes != null)
@ -62,6 +69,9 @@ class AlignmentStep : Step(), KoinComponent {
for (i in 0..<dexCount)
zip.deleteEntry(getDexName(i))
for (path in nativeLibPaths)
zip.deleteEntry(path)
// Write all the files back aligned this time
if (resourcesArscBytes != null)
zip.writeEntry("resources.arsc", resourcesArscBytes, ZipCompression.NONE, 4)
@ -71,6 +81,13 @@ class AlignmentStep : Step(), KoinComponent {
val bytes = file.readBytes()
zip.writeEntry(getDexName(idx), bytes, ZipCompression.NONE, 4)
}
// Write back native libraries aligned to 16KiB page boundary
for ((idx, path) in nativeLibPaths.withIndex()) {
val file = paths.patchingWorkingDir().resolve("$idx.so")
val bytes = file.readBytes()
zip.writeEntry(path, bytes, ZipCompression.NONE, 16384)
}
}
}

View file

@ -15,6 +15,7 @@ object ManifestPatcher {
private const val DEBUGGABLE = "debuggable"
private const val VM_SAFE_MODE = "vmSafeMode"
private const val USE_EMBEDDED_DEX = "useEmbeddedDex"
private const val EXTRACT_NATIVE_LIBS = "extractNativeLibs"
private const val REQUEST_LEGACY_EXTERNAL_STORAGE = "requestLegacyExternalStorage"
private const val NETWORK_SECURITY_CONFIG = "networkSecurityConfig"
private const val LABEL = "label"
@ -91,19 +92,24 @@ object ManifestPatcher {
mapOf(
LABEL to appName,
DEBUGGABLE to debuggable,
REQUEST_LEGACY_EXTERNAL_STORAGE to true
REQUEST_LEGACY_EXTERNAL_STORAGE to true,
VM_SAFE_MODE to true,
USE_EMBEDDED_DEX to true,
EXTRACT_NATIVE_LIBS to true,
)
) {
private var addDebuggable = debuggable
private var addLegacyStorage = true
private var addVmSafeMode = true
private var addUseEmbeddedDex = true
private var addExtractNativeLibs = true
override fun attr(ns: String?, name: String, resourceId: Int, type: Int, value: Any?) {
if (name == NETWORK_SECURITY_CONFIG) return
if (name == REQUEST_LEGACY_EXTERNAL_STORAGE) addLegacyStorage = false
if (name == VM_SAFE_MODE) addVmSafeMode = false
if (name == USE_EMBEDDED_DEX) addUseEmbeddedDex = false
if (name == EXTRACT_NATIVE_LIBS) addExtractNativeLibs = false
if (name == DEBUGGABLE) addDebuggable = false
super.attr(ns, name, resourceId, type, value)
}
@ -152,6 +158,14 @@ object ManifestPatcher {
super.attr(ANDROID_NAMESPACE, VM_SAFE_MODE, android.R.attr.vmSafeMode, TYPE_INT_BOOLEAN, 1)
}
if (addExtractNativeLibs) super.attr(
ANDROID_NAMESPACE,
EXTRACT_NATIVE_LIBS,
android.R.attr.extractNativeLibs,
TYPE_INT_BOOLEAN,
1
)
super.end()
}
}