Android Runtime Resource Overlay with custom attributes

2.4k views Asked by At

I'm trying to use the Runtime Resource Overlay (RRO) mechanism to overlay an xml resource, which is using custom attributes and custom namespace. When building the overlay APK the aapt2 (link) throws an attribute not found error.

How do I make known the custom attribute from the main application to the overlay?
Is it even possible to use custom attributes in an overlay?

Details:
The overlay contains of two files:

AndroidManifest.xml:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="de.test.simpleappoverlay">

    <overlay
        android:targetPackage="de.test.simpleapp"
        android:targetName="Test"/>
</manifest>

and the xml file res/xml/my_config.xml:

<?xml version="1.0" encoding="utf-8"?>
<MyConfig xmlns:app="http://schemas.android.com/apk/res/de.test.simpleapp"
    app:text="hello">
</MyConfig>

<!-- I also tried: xmlns:app="http://schemas.android.com/apk/res-auto" -->

The main application defines the attribute text in res/values/attrs.xml:

...
<declare-styleable name="MyConfig">
    <attr name="text" format="string" />
</declare-styleable>

Furthermore it defines the overlayable tag in res/values/overlayable.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">
    <overlayable name="Test">
        <policy type="public">
            <item type="xml" name="my_config"/>
        </policy>
    </overlayable>
</resources>    

To build the overlay I do this:

aapt2 compile -v --dir app/src/main/res/ -o SimpleAppOverlay.flata

and

aapt2 link -v --no-resource-removal
-I ~/Library/Android/sdk/platforms/android-29/android.jar
--manifest app/src/main/AndroidManifest.xml
-o sao.apk SimpleAppOverlay.flata

Which leads to the following output:

note: including /Users/bernd/Library/Android/sdk/platforms/android-29/android.jar
aapt2 W 09-01 14:33:06 20083 694697 ApkAssets.cpp:138] resources.arsc in APK '/Users/bernd/Library/Android/sdk/platforms/android-29/android.jar' is compressed
note: linking package 'de.test.simpleappoverlay' using package ID 7f note: merging archive SimpleAppOverlay.flata
note: merging 'xml/my_config' from compiled file app/src/main/res/xml/my_config.xml
note: enabling pre-O feature split ID rewriting AndroidManifest.xml:
note: writing to archive (keep_raw_values=false)
note: writing AndroidManifest.xml to archive note: linking app/src/main/res/xml/my_config.xml (de.test.simpleappoverlay:xml/my_config)
app/src/main/res/xml/my_config.xml:2: error: attribute text (aka de.test.simpleappoverlay:text) not found
error: failed linking file resources.

3

There are 3 answers

0
Mackenzie On

I had a similar problem to this where I was trying to overlay an app with custom attributes in Android 10 and have a solution. There are two changes that are needed:

Part 1

It looks like your app name is de.test.simpleapp so your my_config.xml file should look like:

<?xml version="1.0" encoding="utf-8"?>
<MyConfig xmlns:app="http://schemas.android.com/apk/prv/res/de.test.simpleapp"
    app:text="hello">
</MyConfig>

The important piece is specifying the 'prv/res/app.packagename' so it uses the namespace of the base app for the private attributes. If you used 'apk/res-auto' that would not work as it resolves to the name of your app (which in this case is the overlay app de.test.simpleappoverlay) which does not contain the definition of the private attributes.

Part 2

Since you now have a dependency on the main app when linking, you have to include it in the link command with a -I simpleapp.apk (or whatever the APK name is of the base app). Right now you are just including android.jar in the aapt2 link step which only contains the 'android' namespace and attributes. Therefore, you now need to add your base app in the include step so it can link properly against its namespace and attributes.

Like some of the other answers said though, this problem goes away in Android 11, but if you're stuck on Android 10 like I am hopefully this helps.

1
narko On

I don't think including new ids is supported in the current implementation of the RROs (at least in Android Q). Regarding your error, aapt uses the android.jar to generate the apk for your overlay. Since it cannot find your new attribute, it throws an error. For this to work I believe you would need to use a modified android.jar including your attribute. One way of doing this is by modifying the Android SDK in the AOSP and creating your own version that you would then use for the aapt command.

1
Hunter On

Some time ago I switched my AOSP environment from Android 10 to 11. Google made quite a few changes to the Overlay mechanism. To my big surprise these changes fixed the problems I had when trying to "overlay" custom attributes.
With the Android 10 environment I observed while debugging that the Android XML parser returns "null" when trying to read the mentioned attributes. With idmap I was able to confirm that the attributes were present in the overlay and the target app, and that they were properly mapped.
Also all the linker errors were gone.