Android Library With Overridable Resources
When distributing a compiled library for Android, it is sometimes desirable for the developer who will use the library to be able to override some of the resources, for example in order to change an image or to customize some strings.
One solution could be to provide an API to change these images or strings, or to require the user to update the library resources with their data. However, using a Java API to change images and strings may not be convenient, and modifying the library resources could create issues when updating the library or providing it as an AAR file.
In this instance, the best solution may be to allow the developer to add resources in their own project that will override the resources from the library.
The solution provided in this article will show how to use overrideable resources.
When an Android application or library is compiled, the resources are stored in a file, and a reference is created in the R.java file. In this file, each resource entry is in the form of a name/value pair where an ID generated by the compiler is assigned to a resource name integer constant.
At run time, in order to load a resource that may have been overridden by the developer using our library, we need to get its ID based on its name. If the resource doesn't exist in the main application resources, then the resource from the library will be automatically used.
Here’s what it looks like:
getIdentifier(java.lang.String name, java.lang.String type, java.lang.String package)
- “name” is the name of the resource
- “type” is a string representing the type of the resource, for example anim, attr, color, drawable, ID, integer, layout, menu, string, style, etc.
- “package” is the package of the main application.
To get the package of the main application at run time, simply use the getPackageName method from a context.
Once you have the ID, you can load the resource using Resources methods such as:
To get a reference on the Resources object from your application, just use the getResources method from a context
The only potential issue with this solution is that the resources to be overriden must be loaded at run time. This means, for example, that references to resources used in .xml layout can't be overridden. Therefore, if you want a string displayed in a layout to be overridable, you will need to update the content of the UI as it is created (using the onCreate method, for example) by loading the resource using the solution described above.
Note that when using this method, missing resources will not be detected at compilation time, with all the risks this entails.
This technique works for all types of resources: drawable, string, layout, theme, color, etc.
Note that if you use a tool like Proguard to obfuscate your application code, you will need to ensure that the library resource file (R.class) is excluded from the obfuscation, or your application may not work.