Technical docs‎ > ‎

Private Resources in Android Libraries

This page is obsolete. Redirecting to https://developer.android.com/studio/projects/android-library.html#PrivateResources




tl;dr;

Private Resources is a new facility offered by the Android Gradle plugin and Android Studio which lets library authors designate specific resources in their library as “public”, and everything else is implied to be private. The tools then use this information to filter out private resources from code completion, to warn about name conflicts, etc.

The Problem

A library will often contain a number of resources intended only for internal usage by the library; they are not intended to be referenced directly by developers using the library.

Take appcompat for example: it ships with something like 400 resources. Now that it supports Material Design, some of the attributes are clearly intended for use, such as attributes controlling the Toolbar widget etc, but a large number of the resources are involved in implementing the backport of the ActionBar: internal layouts for the different action bar modes, nine-patches for backgrounds, and so on.

Library resources share the same symbol namespace as the user’s own code, and this causes two problems:
  • Name conflicts. If two unrelated libraries (or a library and the developer’s own code) happen to pick the same intuitive name for a resource, many problems can arise. As a simple example, let’s imagine they both define a string message with the same key, one will override the other with completely unrelated and misleading contents; if there are formatting argument mismatches there can be crashes (which is even more likely for overriding layouts where findViewById calls will fail to find id’s to bind to etc.)
  • Noise. Code completion (and other resource name lookup such as in the layout editor property sheet) becomes much harder to use when the namespace is filled up with a lot of resources from libraries that are not interesting (or known) to the developer. Take the appcompat example again: AppCompat ships with over a hundred symbols with the prefix “abc”, so if you’re in the IDE and you’re invoking code completion on @drawable/ to find your launcher icon, the only thing you’ll see are abc_ resources from appcompat since they sort alphabetically to the top!
Note that with AAPT2 problem #1 will eventually go away: When users import libraries in their own namespace, the name conflict goes away. However, the noise problem remains: when you use appcompat, you really only want to see (in the layout editor, in the theme editor, in code completion) the resources the library really meant to expose, not its internal guts.

Private Resources

The private resource mechanism lets developers designate some resources as “public”. When this is done, all remaining resources are considered private: this means that the library itself can use the resource, but clients can not.

(This approach matches the Android Framework: The framework itself ships with both public and private resources; only resources that are explicitly marked as public are exposed in the SDK and are available to developers, and only the framework code itself can reference the other attributes. (Many Google applications used to access them anyway using the special *android syntax, but aapt no longer allows this and the best practice is to copy the resources for private use). Resources are made public in the framework by using the <public> resource type, where you specify the name, type, and assigned constant value.)

Declaring Public Resources

Public.xml

Developers can define resources to be made public in the same way that this is already done in the framework: by adding a <public> declaration in any resource file:
<resources>
    <public name="mylib_app_name" type="string"/>
    <public name="mylib_public_string" type="string"/>
</resources>


As with all other value resources, you can define these in any file, but the convention we’ll encourage via our New Android Library template is to place these in a file named public.xml.

One key difference between this public declaration and the one used in the framework is that in the framework, you also specify the specific R constant you want aapt to assign to it. That attribute does not apply here (and obviously can’t work: the values will have to be adjusted when merged into the final app; otherwise two unrelated libraries could specify the same constant value that would conflict.)

(See the Compatibility section below for how we can start using this in libraries now, without breaking Eclipse or Makefile builds, as well as using earlier Gradle versions than the one which adds support for private resources.)

AAR Packaging

The Android Gradle plugin has been modified such that when building a library, it grabs the public resource definitions and extracts them into a special file, “public.txt”, which is then packaged inside the AAR file next to “R.txt”. This file has a very simple syntax: type + space + name + newline. For the example above, it would be

string mylib_app_name
string mylib_public_string

The builder API has been updated to let clients look up the public symbols for an AAR: it now has a “File getPublicResources()” method which returns the location of the public symbols.

IDE Usage

The IDE needs to make a deliberate decision for each feature whether it wants to know about all resources, or just the public resources. For layout rendering for example, it will need to track all resources, public and private. But for code completion, it should filter the results to only include public resources.

To handle this, the IDE reads the public.txt files from the libraries and uses this to filter resource queries.

Currently (in Android Studio 1.3+) it filters out private resources from

  • Code completion
  • The Theme Editor
Here’s code completion in the IDE in a project that depends on appcompat before private resources was enabled:
Here’s the same code completion invocation now - notice how it’s now showing only the local @dimen resources in my project, not private @dimen resources from appcompat:

Lint Usage

AAPT2 will let developers deal with name conflicts properly. However, in the meantime, if you (accidentally) name your resources the same as a library resource, you’re overriding the library resource, with possibly disastrous results.

Lint now warns about private resources; it uses the same database, and if it sees a resource reference in a project from a resource.

Comments