Accelerating Android Bug Fixes and Version Updates with a Hotfix Patch Framework
Android's fragmented versions and market‑specific policies make bug fixes and version upgrades painfully slow, but by treating the app as a loader and delivering patch files that replace the Application class, dex files, resources, and native libraries, developers can achieve near‑instant, user‑transparent updates without disrupting the normal release flow.
Learning from Others
In recent years Android hot‑patch frameworks have become popular. Early solutions focused on code fixes and fell into two categories: native hook (e.g., AndFix, Dexposed) and Multidex (e.g., Qzone). The Qzone approach inspired the more complete nuwa library.
Chrome's patch‑upgrade model—downloading a patch file and applying it on the next launch—demonstrates how to accelerate bug handling and version iteration on Android by delivering patch files that update the app.
Standing on the Shoulders of Giants
During our technology selection we tried AndFix, which kept up with a production release but suffered from limitations such as inability to modify fields or add classes, maintenance difficulty, and bugs like a white screen after applying a patch. nuwa only supports Java code updates and cannot modify resources or native .so files, so we built our own patch solution.
App Is Just a Loader
Our goal is to support updating all code and resources. The main questions are:
Can the Application class and its dependent business classes be updated?
Can resource files be updated?
How to update native .so files?
We treat the app as a loader: after the system starts the app, a loader decides where to load code and resources. When a new feature or bug‑fix needs to be pushed, we replace the loader’s content.
Supporting Full Code Updates
Because the Application class is loaded at startup and cannot be replaced directly, we proxy its creation. During compilation we modify AndroidManifest.xml to replace the real MyApplication with a placeholder MoaiApplication. At runtime MoaiApplication loads the appropriate dex, resource, and .so files, then hands control back to MyApplication.
Proxy Lifecycle
MoaiApplicationloads the business code, resources, and native libraries, receives the full Android lifecycle, and delegates it to MyApplication. The following diagram shows a simple example.
Missing any lifecycle callback (e.g., registerActivityLifecycleCallbacks) leads to bugs such as lost activity callbacks.
Reflecting Application
To avoid writing a full proxy, we replace the system’s ContextWrapper.mBase reference via reflection, effectively swapping the Application instance at runtime. This eliminates the need for manual lifecycle delegation.
Dex Splitting
Patch files contain a changed patch.dex. We split the APK dex files into two groups: the loader dex ( classes.dex) that contains only the patch library, and business dex files ( classes[N].dex) that hold the rest of the code. Updating a business dex simply replaces the corresponding classesN.dex and the loader loads the new version.
How to Load Updated Code?
When a dex file is updated, the loader loads the new file. We initially used Google’s Multidex and extended DexPathList.dexElements, but some devices (e.g., Samsung S6 on Android 5.0.2) failed to load the extended dex due to multithreaded startup. We therefore abandoned Multidex and hacked the system ClassLoader hierarchy.
ClassLoader Hack
All threads share a single ClassLoader. By inserting our custom loader into the PathClassLoader / BootClassLoader chain, we ensure that every thread uses the patched loader, solving the multithread loading issue.
Instant Run Inspiration
Instant Run inserts an IncrementalClassLoader as the parent of DelegateClassLoader, which in turn delegates to PathClassLoader. This class‑loader chain guarantees that both business code and patch library code are found.
How to Update Resources?
We reflect the system Resources object to replace its internal AssetManager with one that loads resources from the updated APK. This supports changes to strings, animations, drawables, colors, layouts, etc. Modifying the AndroidManifest.xml at runtime currently does not allow adding new components such as Activities.
How to Update .so Files?
Native libraries are normally loaded with System.loadLibrary. We intercept the class‑loader’s nativeLibraryDirectories (pre‑Android 6.0) or nativeLibraryPathElements (Android 6.0+) and prepend a custom directory containing the patched .so files, so the loader finds and loads the updated native library first.
Patch Generation and Application
We generate a patch by diffing two APKs and packaging changed files. At runtime the app merges the patch with its own sourceDir, performs concurrent dex optimization to avoid process kill, and loads the new dex, resources, and native libraries on the next launch.
Advantages and Limitations
Full support for Java code, resources, and native .so patches; developers continue normal release cycles.
Simple integration—only three lines in build.gradle are required.
Patch files can be large; download errors may affect patch rollout, so we are exploring better diff algorithms (e.g., Courgette).
Evolution and Thoughts
A patch framework should do more than fix bugs; it must be easy to adopt, not disrupt existing workflows, and enable continuous delivery. By delivering patches automatically, we can reduce crash rates, accelerate feature rollout, and gather user feedback faster. Our solution is already in trial on three versions of WeChat Reading.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Tencent TDS Service
TDS Service offers client and web front‑end developers and operators an intelligent low‑code platform, cross‑platform development framework, universal release platform, runtime container engine, monitoring and analysis platform, and a security‑privacy compliance suite.
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.
