Fusing Two APKs via Tinker: Compile-Time Skeleton Grafting and Runtime Takeover Produce One App
Teams that cannot modify a finished plugin APK can now deliver a tiny first install that later becomes the full native app, without fighting AMS/PMS or requiring the plugin team to adopt a plugin framework. The cost is a patch nearly as large as the plugin, high peak disk usage, and reflective Application swaps that need regression testing on every Android version.
Traditional Android pluginization hooks the system AMS/PMS and runs a plugin inside a container, which breaks on recent Android versions. This scheme inverts the idea: it treats the plugin APK as the host's "next version" and uses Tinker's diff and patch machinery to merge them.
At build time, the plugin is decompiled with apktool. Its manifest is assimilated into the host, all its components are replaced with empty stub Java classes, a BFS picker extracts only the resources the manifest directly references, and AAPT2 stable-ids locks resource IDs between the two packages. The result is a ~40MB baseline host that already carries the plugin's legal component declarations. A full diff against the original 2GB plugin produces a patch containing every DEX, resource, asset, and SO the plugin needs.
At runtime, Tinker loads that patch, then a proxy Application reflects the plugin's real Application into ActivityThread, swaps paths so hardened shells read the patch's sourceDir, and routes the launcher to the plugin's main Activity. The scheme works without touching plugin source, but the patch is nearly the size of the plugin, disk peaks reach about 4GB, and reflective substitution into ActivityThread must be re-verified each Android release.
The approach effectively treats the plugin as a legitimate new version of the host, so all the hard DEX/resource/asset merging is offloaded to Tinker's battle-tested patch pipeline; the original engineering risk shifts to resource-ID stability and global reference substitution.
Zero source modification does not translate to zero maintenance: reflecting into ActivityThread internals will still break across Android versions, and the fallback only reduces the blast radius, not the need for per-release regression checks.
The 1+1=1 restriction means this is a specialized solution, not a general plugin framework; it trades flexibility for a frictionless path to fuse a single large game or app into a lightweight host.
By patenting the plugin as a hot-update patch, the scheme makes the patch size nearly equal to the plugin, so it optimizes time-to-first-frame and conversion rate, not bandwidth or storage efficiency.