Inlining R Files for Android Package Size Optimization
This article explains how Android developers can reduce APK size by inlining R files, detailing the generation of R.java and R.txt, the causes of oversized R files, and step‑by‑step bytecode transformation techniques using ASM to replace resource ID lookups with constant values.
Preface & Background
Package size is a frequent target for performance optimization, and many "killer" solutions have emerged, such as dynamic .so libraries and R file inlining. Since the dynamic .so approach was covered previously, this article focuses on another size‑reduction technique: inlining the R file.
In Android development, resources are accessed via R.xx.xx . While convenient, the R file can bloat the APK; a medium‑sized project may have an R file of up to 10 MB, with 4–5 MB being duplicate or unnecessary entries. This article explores the lifecycle of the R file and how to streamline it.
R File Generation
During the Android build process, files under res/ are compiled and compressed by the aapt tool, which generates resource IDs, an R.java file to store those IDs, and a resource.arsc file that maps IDs to actual resources.
The R file contains several static final inner classes (e.g., anim , attr , layout ) that correspond to sub‑directories in res/ . Each resource ID is a 32‑bit hexadecimal integer, such as 0x7f010000 , where the first byte (7f) indicates the resource belongs to the app, the second byte indicates the type (01 for anim), and the last two bytes represent the index.
Because the fields are static final, the compiler can inline them, replacing R.anim.abc_fade_in with the literal integer value.
For library modules or AARs, the build system generates a separate R.txt (or R.def.txt ) that records the module’s resource mappings. These mappings are later merged into a global R file to avoid ID collisions across modules.
Why R Files Grow Large
Each module generates its own R entries, and the global R file aggregates them. In a multi‑module project, duplicated entries cause the R file size to balloon. While the app module’s R file can be removed by ProGuard if unused, library R files referenced by the app cannot be stripped, limiting size‑reduction opportunities.
R File Inlining Solution
R.txt
The R.txt file stores the final resource ID mappings. In Gradle 3.4.1, it is generated under build/intermediates/symbols/.../package-aware-r.txt . The path may vary across AGP versions.
Bytecode Replacement
Normally, a call like setContentView(R.layout.activity_main) compiles to bytecode that loads the constant ID via LDC 2131427356 . In a library module, the same call compiles to a GETSTATIC instruction that reads the static field from the module’s R class.
By reading R.txt to obtain the integer ID (e.g., 0x7f0b001d → 2131427357) and replacing the GETSTATIC with an LDC instruction, the library no longer needs its own R class at runtime, allowing ProGuard to remove it.
if(node.opcode == Opcodes.GETSTATIC && node.desc == "I" &&
node.owner.substring(node.owner.lastIndexOf('/') + 1).startsWith("R$") &&
!(node.owner.startsWith(COM_ANDROID_INTERNAL_R) || node.owner.startsWith(ANDROID_R))) {
println("get node ")
def ldc = new LdcInsnNode(2131427357)
method.instructions.insertBefore(node, ldc)
method.instructions.remove(node)
}This ASM tree API snippet demonstrates the transformation.
Extensions
Several open‑source tools, such as Bytex Booster, automate this inlining for multiple R files. However, scenarios that reflectively read R fields (e.g., using R.drawable.xxx via reflection) cannot be inlined and must be whitelisted.
public static int getId(String num){
try {
String name = "drawable" + num;
Field field = R.drawable.class.getField(name);
return field.getInt(null);
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}Conclusion
By inlining R files, developers can shrink APK size by roughly 5 MB. Projects using AGP 4.1.0 or later can enable this feature without third‑party libraries, as it is now officially supported by the Android Gradle Plugin.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
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.