One of the most persistent frustrations encountered when modifying Android packages is encountering build failures during the recompilation stage. While bytecode edits in Smali often assemble without issue, touching XML layouts, drawables, or strings frequently triggers baffling resource allocation failures. Error messages such as No resource identifier found or AAPT2 complaining of symbol redefinitions usually trace back to a single source: resource table misalignment and public.xml conflicts.
In this guide, we dive deep into how Android stores compiled resources, why disassembly tools struggle with resource IDs, and actionable techniques to resolve resource table discrepancies cleanly.
How Android Manages Resources: The 0x7F Format
When an Android project builds, the Android Asset Packaging Tool (AAPT or AAPT2) compiles raw XML and asset files into the binary format stored inside resources.arsc. Each compiled resource receives a unique 32-bit integer identifier structured as follows:
- Package ID (8 bits): Typically
0x7ffor application-specific resources (or0x01for system framework resources). - Type ID (8 bits): Denotes the resource type, such as
0x04for strings,0x08for drawables, or0x0bfor layouts. - Entry ID (16 bits): The incremental index of the entry within that particular resource type, starting from
0x0000.
For example, a string resource named app_name might resolve to 0x7f100001. The source code and Smali bytecode reference this hex constant directly, mapping back to the string via the resource table.
The Core Problem: Disassembly and public.xml
When standard decompilers like Apktool disassemble an APK, they extract resources.arsc into human-readable XML files and generate a critical tracking file: res/values/public.xml. This file explicitly maps every resource name to its original static hexadecimal ID:
<!-- Example entry in res/values/public.xml -->
<public type='string' name='app_name' id='0x7f100001' />
<public type='drawable' name='ic_launcher' id='0x7f080005' />
<public type='layout' name='activity_main' id='0x7f0b0012' />Resource collisions typically occur in two scenarios:
- Adding New Resources Incorrectly: Inserting a new layout or string into
strings.xmlwithout properly registering it inpublic.xml, causing AAPT2 to generate an ID that collides with an existing static entry. - Modifying Existing Resource Types: Deleting or renaming an entry while leaving stale references in
public.xmlor Smali bytecode, causing orphaned ID lookups at compile time.
Troubleshooting Common Recompilation Errors
1. 'No resource identifier found for attribute'
This error commonly manifests when custom view attributes or AndroidX theme declarations lose their namespace binding during decompression. To resolve this, inspect the declaring tag inside your layout file and ensure the correct XML namespace is declared:
<!-- Ensure custom schema declarations are properly linked -->
xmlns:app='http://schemas.android.com/apk/res-auto'
xmlns:android='http://schemas.android.com/apk/res/android'2. AAPT2 Collision: 'duplicate symbol'
When AAPT2 detects duplicate IDs, you will see an error indicating that a symbol with the same name or identifier already exists. Open res/values/public.xml and search for the offending name. If you added a new resource manually, do not assign an arbitrary ID that overlaps with the existing incremental sequence. Instead, locate the highest hex ID under that resource type and increment by 1:
<!-- Previous highest string ID was 0x7f100042 -->
<public type='string' name='custom_feature_enabled' id='0x7f100043' />Synchronizing XML Changes with Smali Bytecode
Remember that updating or introducing a resource requires corresponding updates wherever bytecode consumes it. For example, if you introduce a new string ID 0x7f100043 and want to load it dynamically inside an Activity, update the corresponding Smali instruction with the exact literal:
# In your modified Smali method
const v1, 0x7f100043
invoke-virtual {p0, v1}, Landroid/app/Activity;->getString(I)Ljava/lang/String;
move-result-object v0If the Smali constant points to an ID that does not exist in public.xml or resources.arsc, the app will compile but crash at runtime with a Resources$NotFoundException.
Streamlining the Process with APKTool Studio
Managing resource IDs manually across large APKs with hundreds of values files can quickly become error-prone. Modern web-based environments significantly reduce this friction.
APKTool Studio provides an integrated browser-based workflow that decompiles APK packages, presents an organized directory tree for resource and Smali modification, and executes recompilation using clean, modern AAPT2 toolchains in isolated sandbox environments. It flags malformed XML tags, missing resource IDs, and namespace misconfigurations directly before packaging and signing, eliminating the tedious cycle of local command-line errors.
Summary and Best Practices
- Never change existing IDs: Keep existing entries in
public.xmlintact to prevent breaking precompiled Smali references. - Append incrementally: When introducing new resources, find the maximum ID in the specific type category and increment systematically.
- Clean framework caches: If decompiling APKs from manufacturer-specific skins (MIUI, OneUI), make sure framework dependencies are loaded to prevent unresolved framework attribute collisions.
- Validate signatures: Always run
zipalignand re-sign with APK Signature Scheme v2/v3 after resolving resource issues to ensure smooth installation.