Mobile Development 26 min read

Solving Android Plugin Resource ID Conflicts with a No‑Resource‑Fixation Approach

This article explains the problem of resource ID mismatches when Android plugins use host resources, reviews existing resource‑fixation solutions, and presents a novel “no‑resource‑fixation” method that dynamically maps host IDs at compile‑time and runtime to keep plugins stable across host updates.

ByteDance Terminal Technology
ByteDance Terminal Technology
ByteDance Terminal Technology
Solving Android Plugin Resource ID Conflicts with a No‑Resource‑Fixation Approach

1. Dynamic Resource Handling in Android Plugin Frameworks

Android has many plugin and hot‑fix frameworks that aim to load code, resources, and native libraries dynamically. While the underlying principles are similar, each content type (dex, res, so) has multiple implementation options.

Terminology

Host : The app installed on the device; its code is fixed at install time.

Plugin : An independent APK (or patch) that contains classes, resources, and native libraries to be loaded by the host.

Java code : Source code before compilation; after compilation it becomes dex (the article notes the simplification of calling it class before dex conversion).

Typical ways to achieve resource dynamism are:

Create a separate Resources instance for each plugin or add the plugin’s resource path to the host’s AssetManager .

Modify the packageId part of resource IDs during compilation with aapt2 to avoid conflicts.

Use aapt2 parameters to fix host resources so that their IDs remain unchanged after host upgrades.

Although these techniques are mature, developers often complain about the overhead of resource fixing.

2. Introduction to Android Resources

2.1 Resource ID Structure

After compilation each resource gets a unique 8‑digit hexadecimal ID: 0xPPTTEEEE , where:

PP : Package ID (01 for system, 7f for host, others for custom packages).

TT : Type ID (anim, drawable, string, etc.).

EEEE : Entry ID within the package‑type pair.

IDs are assigned alphabetically, so adding a new resource can shift the IDs of subsequent resources. aapt2 provides parameters to intervene in this allocation, a technique known as “resource fixing”.

2.2 Accessing Resources

Resources can be accessed in two ways:

[<package_name>].R.<resource_type>.<resource_name>

or in XML:

@[<package_name>:]<resource_type>/<resource_name>

Both ultimately resolve to the numeric ID at runtime.

2.3 Simplified Resource Compilation Flow

When an app depends on third‑party AARs, the build process downloads the AARs, compiles and links all resources with aapt2 to produce R.jar and ap_ files, then compiles Java code together with R.jar . Because the fields in R.jar are final , the host module’s resource references are inlined as numbers, while library modules keep the R reference.

3. Plugins Using Host Resources

When a plugin references a host resource (e.g., @drawable/icon ), the host compiles the resource to a fixed ID (e.g., 0x7f010001 ). The plugin’s compiled XML and Java code also contain this numeric ID, so at runtime the plugin can locate the host resource.

3.1 Problems with Host Resource Usage

If the host adds or removes resources, the IDs of existing resources may shift. A plugin built against an older host version may then look up the wrong ID, causing visual glitches or crashes.

3.2 Existing Solution – Resource Fixing

Industry practice is to fix the IDs of all host resources that plugins use, ensuring they never change across host releases. However, this approach has drawbacks:

When a host integrates multiple frameworks (plugins, hot‑fix, game re‑packaging), each may try to fix resources independently, leading to ID conflicts.

Supporting multiple hosts for a single plugin becomes impractical because each host would need its own fixed‑resource configuration.

3.3 Proposed New Approach – No‑Resource‑Fixation

The authors propose a method that avoids fixing IDs altogether. The idea is to map the plugin’s hard‑coded IDs to the current host IDs at runtime using Resources#getIdentifier . This requires cooperation at both compile‑time and runtime.

4. Compile‑Time Work for the No‑Fixation Scheme

4.1 Handling Java Code

During compilation, the R.jar is generated. By removing the final modifier from all ID fields, the plugin’s Java code will keep the R reference instead of being inlined. A subsequent Transform scans for these R references and replaces them with method calls that resolve the correct host ID at runtime.

4.2 Handling XML Resources

XML IDs cannot be altered at compile time because they are already compiled to numbers. The solution is to record, during compilation, every host resource name used in plugin XML files together with its original ID. At runtime the plugin reads this mapping and rewrites the binary XML (AXML) and resources.arsc files to replace the old IDs with the host’s current IDs.

5. Modifying APK Resource Files

5.1 Editing Binary XML (AXML) and ARSC

Both AXML and resources.arsc are binary formats. By parsing the byte array, locating the 4‑byte resource ID fields, and substituting the new ID, the file size does not change, so a simple byte‑level replacement is sufficient.

5.2 Updating the APK

Two strategies are discussed:

Re‑compression : Extract the ZIP entries, modify them, and re‑zip the APK. This is simple but slow, especially on older Android versions.

Direct Byte‑Array Modification : Locate the exact offset of each target file inside the APK (using the ZIP central directory), decompress only the needed entries, apply the ID replacement, and write the bytes back without changing the overall layout. This approach reduces the modification time to a few hundred milliseconds.

Both methods rely on standard Java APIs such as RandomAccessFile and ZipFile . The authors note that keeping the affected XML/ARSC files uncompressed during the build eliminates length‑change issues.

6. Conclusion

The presented “no‑resource‑fixation” technique allows a plugin to run on any host version without requiring the host to lock resource IDs. It introduces a small increase in APK size (≈20 KB for a 30 MB plugin) and a negligible runtime overhead, which can be mitigated with caching.

The solution has been integrated into the Volcano Engine MARS development suite and is available to developers.

For more product information, click the original article link.

Mobile DevelopmentAndroidpluginResource Managementdynamic loadingAAPT2
ByteDance Terminal Technology
Written by

ByteDance Terminal Technology

Official account of ByteDance Terminal Technology, sharing technical insights and team updates.

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.