Mobile Development 11 min read

APK Package Size Optimization and Resource Obfuscation for Android Plugins

To keep Android plugins lightweight as they grow, developers should analyze and obfuscate resource files—using a custom AndroidResGuard extension that adds a fixed package ID and a mapping table protocol—to shrink the resources.arsc constant pool, integrate the changes via Gradle, verify with gray releases, and achieve roughly an 8% size reduction while ensuring whitelist compliance.

Baidu Geek Talk
Baidu Geek Talk
Baidu Geek Talk
APK Package Size Optimization and Resource Obfuscation for Android Plugins

When to Optimize Package Size

Package size optimization is usually unnecessary during the early stage of an app when the codebase is small and the APK is lightweight. As the business matures and features increase, the APK size grows, making optimization more valuable.

Impact of Increased APK Size

1. For a full app, a larger download size reduces conversion rates; for a plugin (e.g., Baidu Live internal plugin) the impact is on download time and cold‑start latency.

2. Channel partners may impose higher fees for larger APKs because they require more ROM space and longer installation times, degrading user experience.

3. Larger packages, whether app or plugin, lead to longer installation and OAT compilation times (pre‑Android 9).

Composition of an APK

An Android APK consists of:

Code: class.dex

Native libraries: lib/

Resources: resources.arsc , res/ , assets/

Signature information: META-INF/

To control APK size, focus on the dex files, native libraries, and resource data. Native libraries can be downloaded on‑demand; this article concentrates on resource optimization.

Resource Optimization

Using Android Size Analyzer, developers can generate a ranked list of image resources. After analysis, images can be compressed, moved to cloud control, converted to WebP, replaced with vectors, or removed if redundant. The article mainly discusses resource obfuscation based on AndroidResGuard with custom extensions.

Why a Custom Extension?

The original tool does not support plugin resource obfuscation. Plugins need a fixed package ID in resource IDs to avoid conflicts with the host:

[<package_name>. ]R.<resource_type>.<resource_name>
针对插件 //
additionalParameters "--package-id", "0x61", "--allow-reserved-package-id"

Resource Mapping Table Protocol

The obfuscation works by mapping long resource strings to short ones, reducing the constant‑pool size of resources.arsc . Adding a package ID without proper protocol support caused errors, which were solved by extending the ARSC protocol.

Implementation Overview

The solution consists of three parts: design & implementation, QA pipeline configuration, and gray‑release testing.

1. Design & Implementation

The project required a clear understanding of the existing codebase, especially the resource obfuscation rules and whitelist handling. The core modules are:

Configuration module

Plugin module

Resource‑mapping obfuscation module

Configuration parameters (Gradle plugin settings):

mappingFile = file("./resource_mapping.txt")
    use7zip = false
    useSign = false
    // Keep original resource paths, only obfuscate names
    keepRoot = true
    // Reduce string pool size by obfuscating arsc name column
    // fixedResName = "arg"
    // Merge duplicated resources (use with caution)
    mergeDuplicatedRes = true
    nightmode_pattern = "_1" // night mode config
    // Add basic SDKs to whitelist
    whiteList = []

Dynamic parameters for plugin‑specific fix IDs are generated by the following Groovy script:

// Generate whitelist for fix files
def generateWhiteList() {
    def fixFile = file("host-res-fix/${rootProject.ext.plugin_fix_file_map[host]}")
    def resGuard = file("resguard/res_guard_config.xml")
    def resproguard = new XmlParser().parse(resGuard)
    def issueNode = new NodeBuilder().issue(id: 'whitelist', isactive: true)
    resproguard.issue[0].replaceNode(issueNode)
    fixFile.eachLine { line ->
        // TODO: generate whitelist entries
    }
    new XmlNodePrinter(new PrintWriter(resGuard)).print(resproguard)
    return resGuard
}

2. Resource Mapping Table Read/Write

The core logic reads the ARSC structure, modifies it, and writes it back:

private void writeLibraryType() throws AndrolibException, IOException {
    checkChunkType(Header.TYPE_LIBRARY);
    int libraryCount = mIn.readInt();
    mOut.writeInt(libraryCount);
    for (int i = 0; i < libraryCount; i++) {
        mOut.writeInt(mIn.readInt()); // packageId
        mOut.writeBytes(mIn, 256); // packageName
    }
    writeNextChunk(0);
    while (mHeader.type == Header.TYPE_TYPE) {
        writeTableTypeSpec();
    }
}
private void readLibraryType() throws AndrolibException, IOException {
    checkChunkType(Header.TYPE_LIBRARY);
    int libraryCount = mIn.readInt();
    int packageId;
    String packageName;
    for (int i = 0; i < libraryCount; i++) {
        packageId = mIn.readInt();
        packageName = mIn.readNullEndedString(128, true);
        System.out.printf("Decoding Shared Library (%s), pkgId: %d\n", packageName, packageId);
    }
    while (nextChunk().type == Header.TYPE_TYPE) {
        readTableTypeSpec();
    }
}

3. QA Pipeline Configuration

The modified APK is processed with a Gradle task:

./gradlew :app:resguardUseApk -PHOST=${assemble_host} -PMODE=debug

Because the modification touches many internal files, the release uses single‑gray verification to ensure stability. The optimization yields an 8% size reduction and is already applied to multiple plugins.

4. Cautions

When accessing resources by name, the names must be whitelisted. It is recommended to use a lint rule to scan for getIdentifier calls:

fixedResId = context.getApplicationContext().getResources()
        .getIdentifier(resName, null, null);
uri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://"
                  + resources.getResourcePackageName(model) + '/'
                  + resources.getResourceTypeName(model) + '/'
                  + resources.getResourceEntryName(model));

Related Links

• Android Resource Documentation

• AndResGuard Project

Mobile DevelopmentAndroidGradle PluginResource ObfuscationAPK size optimization
Baidu Geek Talk
Written by

Baidu Geek Talk

Follow us to discover more Baidu tech insights.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.