Mobile Development 31 min read

How to Dynamically Manage Android Resources and Shrink APK Size

This article explains the design and implementation of a dynamic resource management system for Android apps, covering the motivation for reducing APK size, the architecture of the dynamicresbase, dynamicrescore, and dynamicresplugin modules, resource loading and application processes, Gradle plugin tasks, code transformation, and practical tips for handling .so libraries.

Huolala Tech
Huolala Tech
Huolala Tech
How to Dynamically Manage Android Resources and Shrink APK Size

Overview

Dynamic resource management system used by Huolala to manage offline .so, animation, and font files, aiming to reduce APK size.

Motivation

APK size growing due to many .so libraries (over 35, each for arm64‑v8a and armeabi‑v7a).

Low‑frequency resources can be downloaded at runtime instead of being packaged.

Key Features

Resource classification (fonts, frame animations, .so, custom files).

Unified loading API for all resource types.

Configurable packaging via a Gradle plugin.

Architecture

Three modules:

dynamicresbase : common utilities such as MD5, zip handling, and the DynamicPkgInfo entity.

dynamicrescore : provides loading and application of resources (fonts, frame animations, .so, custom).

dynamicresplugin : Gradle plugin that performs resource packaging.

dynamicrescore is organized into five layers: external interface, resource application, loading flow (state‑machine), interface isolation, and concrete implementation.

Resource Loading Flow

Check if the resource version matches the local database; if so, verify local files.

If versions differ, start download.

Verify downloaded file (MD5, length, name).

If the file is a zip, unzip it.

Verify each extracted file.

Resource Application

Fonts are applied by creating a Typeface and setting it on a TextView; frame animations are applied via AnimationDrawable; .so files are loaded through a custom loader that handles missing libraries gracefully.

.so Dynamic Loading

The system determines the device’s supported ABIs (Build.SUPPORTED_ABIS) and selects the matching .so package. After download and verification, the .so directory is injected at the head of the ClassLoader’s nativeLibraryPathElements array using reflection, or the Relinker library is used to handle dependency resolution on Android N+.

private static void install(ClassLoader classLoader, File soFolder) throws Throwable {
    Field pathListField = findField(classLoader, "pathList");
    Object dexPathList = pathListField.get(classLoader);
    Field nativeLibraryDirectories = findField(dexPathList, "nativeLibraryDirectories");
    List<File> libDirs = (List<File>) nativeLibraryDirectories.get(dexPathList);
    libDirs.add(0, soFolder);
    // Additional reflection steps for different Android versions omitted for brevity
}

Gradle Plugin (dynamicresplugin)

The plugin defines three main tasks:

TransformTask : uses ASM to replace System.loadLibrary calls with a custom SoLoadUtil.loadLibrary method.

DeleteAndCopySoTask : removes .so files from the APK during the build and copies them to a configurable external directory.

ZipResTask : compresses fonts, frame animations, and .so files, generates a DynamicPkgInfo Java class via JavaPoet, and optionally uploads the artifacts.

Task execution order is configured in dynamic_config.gradle, which also controls scanning rules, ABI filters, ignore lists, and whether to run in release builds.

// Example of dynamic_config.gradle snippet
dynamic_config = [
    is_replace_load_library: false,
    is_delete_so: false,
    is_zip_res: false,
    is_release_type: isReleaseBuildType(),
    create_java_pkg_name: 'com.test',
    // ... other configuration entries ...
]

Implementation Highlights

Key code pieces include the ASM SystemLoadMethodVisitor that swaps the target method, the reflection‑based install method that injects native library paths, and the use of the Relinker library to resolve .so dependencies on newer Android versions.

Optimization Results

Applying the dynamic resource management system reduced the Huolala user‑side APK from 54 MB to 46 MB, achieving an 8 MB size reduction.

References

https://www.jianshu.com/p/260137fdf7c5 https://mp.weixin.qq.com/s/X58fK02imnNkvUMFt23OAg

Dynamic resource architecture diagram
Dynamic resource architecture diagram
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

AndroidDynamic LoadingGradle PluginAPK Optimization
Huolala Tech
Written by

Huolala Tech

Technology reshapes logistics

0 followers
Reader feedback

How this landed with the community

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.