Non‑intrusive Migration of Business Libraries to Android Dynamic Feature Modules
This article explores the motivations, methodology, and practical implementation of converting existing Android business libraries into Dynamic Feature modules with minimal intrusion, covering Android App Bundle basics, build tools, dependency handling, resource merging, Arouter integration, and performance gains achieved through parallel and incremental builds.
The article introduces the need to transform business libraries into Dynamic Feature projects to address long local compile times, vendor package size limits, and the desire for lightweight promotional packages. It outlines four main motivations: faster development builds, compliance with a 45 MB vendor limit, smaller promotional bundles, and early adaptation to the upcoming aab format support in Huawei App Market.
Android App Bundle Overview
Google Play allows multiple APK splits for different device configurations, but developers often upload a single universal APK. The Android App Bundle (.aab) solves this by enabling dynamic delivery of device‑specific APKs. BundleTool can build an .apks archive from an .aab and split it into multiple APKs for various densities, CPU architectures, and languages.
java -jar bundletool-all-1.0.0.jar build-apks --bundle=app.aab --output=my_app.apksAfter extraction, the splits folder contains the device‑specific APKs. These can be installed on a device with:
java -jar bundletool-all-1.0.0.jar install-apks --apks=my_app.apksADB can list the installed split APKs:
adb shell pm path com.sampleDynamic Feature Introduction
Dynamic Feature modules are added via the com.android.dynamic-feature plugin and produce a separate APK. The article asks whether a business library can be turned into a Dynamic Feature to meet the three goals mentioned earlier.
Dependency Relationships
Feature modules depend on the base app; the base cannot depend on features. The base produces a base APK, each feature produces its own feature APK.
If multiple features share a common library, that library must be added to the base dependency tree, ensuring shared code ends up in the base APK while feature‑specific code stays in the feature APK.
Resource Merging and Access
During the build, all feature manifests are merged into the base. Resources referenced in a feature must be placed in a library accessible to the base. Accessing resources across modules requires using the appropriate package’s R class. The article explains how to resolve conflicts by referencing base R for shared resources and traversing both base and feature resources when needed.
Non‑intrusive Transformation Approach
The proposed solution adds a thin Dynamic Feature “shell” project for each business library. The shell applies the dynamic‑feature plugin, depends on the base app, and includes the original AAR libraries. This avoids massive code changes and keeps existing module boundaries.
To handle resource‑access issues, a custom Gradle plugin uses ASM bytecode manipulation to:
Collect feature R resources and replace missing ones with the base package name.
Fix findViewById calls when IDs exist in both base and feature.
Correct getResources().getIdentifier calls by using basePackageName+featureModuleName .
Adjust onClick ID checks via resource name lookup.
A whitelist limits processing to specific classes, minimizing build impact.
Arouter Registration Issue
Since Arouter’s annotation processor does not run in a Dynamic Feature, the article proposes:
Relying on the AARs (which already contain generated Arouter classes) rather than the feature shell.
Reflectively invoking ARouter.getInstance().register() in the feature’s Application.onCreate using ASM.
Initializing the feature application from the base application.
Results
The non‑intrusive conversion enables parallel base and feature builds, reducing full‑build time and achieving 60‑70% faster incremental builds. A custom Gradle task caches all APKs after a full build; during incremental builds only the changed feature APKs are rebuilt and installed together with the cached base APKs using adb install-multiple (note: not supported on Oppo/Vivo devices).
adb install-multiple base.apk feature1.apk feature2.apkConclusion
Android App Bundle with Dynamic Feature modules solves multi‑APK distribution problems. The article demonstrates a practical, low‑impact method to migrate business libraries to Dynamic Feature projects, improving build speed, enabling modular delivery, and laying groundwork for vendor‑specific and promotional packages.
Future Work
Since Google Play Core’s dynamic delivery API is unavailable in China, the next step is to implement a custom plugin‑based dynamic delivery mechanism to produce vendor‑specific and promotional bundles.
58 Tech
Official tech channel of 58, a platform for tech innovation, sharing, and communication.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.