Android Runtime Resource Overlay with custom attributes - android

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.

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.

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.

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.

Related

Android instrumented test - test resource not resolved

I want to have androidTest resources specific to each app flavor. I found an answer on this site that indicated you can just make a resource directory androidTestFlavorName and it will be managed like all the other resources. So I have a directory app/src/androidTestFlavorName/res/values and a file strings.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="test_sec_code">aStringValue</string>
</resources>
I have a test class app/src/androidTest/java/com/company/package/StartupTest.kt. In that class:
val code = context.getString(R.string.test_sec_code)
test_sec_code is red, so the IDE doesn't like it, and the compiler reports: Unresolved reference: test_sec_code
My selected build variant is flavorNameDebug. So am I setting up these resources wrong, or is my goal not possible?
Edit:
I tried putting the resource in app/src/androidTest/res/values/strings.xml and it can't be found there either. Surely there must be a way to define test resources right? Hello, is this thing on?

How can I exclude blocks in XML files using CPD?

In a large project multiple android resources are used. It now happens that there are resources copied. I want to detect these copies using CPD. Currently I'm using the following command:
./run.sh cpd --language xml --minimum-tokens 20 --files $RES_FOLDER
Unfortunately most XML files contains at least a declaration line:
<?xml version="1.0" encoding="UTF-8" ?>
followed by some header:
<!--
-- Copyright 2017, all rights reserved.
-->
There is an option --skip-blocks-pattern but it seems to be ignored.
Anybody any hints?
I fear this can't be done at the moment.
The --skip-blocks-pattern is a cpp only flag, used to ignore #if 0 ... #endif blocks.
There are plans to provide the ignore support through comments on all / most supported languages in the near future. We recently added such support experimentally on Java and so far had good results, so we may soon promote it across the board.

I have two attr in appcompat_v7 and FloatingButtonAction

My project contains these two libraries , but for some reason I get an error when I want to run it on my device :
The error is as follows:
workspace_desarrollo\Librerias\FloatingActionButton\res\values\attrs.xml:6: error: Attribute "color" has already been defined
Look at both libraries and found that both are defined . What I did was rename the FAB library and reads as follows:
<attr name="colortem" format="color"/>
Everything normal, but when you run the APP , the button shows me with white background. There are 3 buttons that use and puts three white background.
Previously I did not have this problem, but I had to change PC and when you import the new workspace projects started dating this error.
The appcompat_v7 this in : target=android-21
The FloatingActionButton this in :
target=android-19
android.library=true
android.library.reference.1=../nineoldandroids
My project is in :
target=android-21
android.library.reference.1=../../Librerias/FloatingActionButton
android.library.reference.2=../../Librerias/appcompat
android.library.reference.3=../../Librerias/google-play-services_lib
I hope you can help me.
Thank You
PD : I'm thinking about starting to develop android studio , but I'm not entirely convinced
Remove the colortem attribute definition, the other one will be used. Otherwise you'd have to change all R.attr.color references inside FAB library to R.attr.colortem as well.

Android Lint: how to ignore missing translation warnings in a regional locale string file that purposely only overrides some default translations?

Is it possible to translate some strings, but not all, in a separate resource file without Lint complaining about MissingTranslation?
For example: my app's strings are all in res/values/strings.xml. One of the strings is
<string name="postal_code">Postal Code</string>
Since "postal code" is usually called "zip code" in the US, I want to add another resource res/values-en-rUS/strings.xml with contents:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="postal_code">Zip Code</string>
</resources>
However, Lint complains about other strings in values/strings.xml but not in values-en-rUS/strings.xml
I realize you can suppress the warnings by specifying tools:ignore in values/strings.xml. But this is undesirable because the Lint warning is actually useful when translating to another language.
Instead, is it possible to suppress the warning in the values-en-rUS/strings.xml file, as in, telling Lint not to use that file as criteria when looking for missing translations?
A nice way to disable MissingTranslations check is to add the option in module specific build.gradle file .
android {
lintOptions{
disable 'MissingTranslation'
}
//other build tags
}
If the strings are not present in locale specific Strings file, it will take the strings from the default file which generally is strings.xml.
I found a better solution according to this answer: https://stackoverflow.com/a/13797364/190309
Just add ignore="MissingTranslation" to your string.xml, for example:
<?xml version="1.0" encoding="utf-8"?>
<resources
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="MissingTranslation" >
<!-- your strings here; no need now for the translatable attribute -->
</resources>
Lint supports partial regional translations, but needs to know what language the default strings are. That way, it can distinguish a partial regional translation from missing translations in a different locale.
To specify the locale in values/strings.xml:
<resources xmlns:tools="http://schemas.android.com/tools" tools:locale="en">
Quote from the lint command-line tool, when running lint --show:
By default this detector allows regions of a language to just provide a
subset of the strings and fall back to the standard language strings. [...]
You can tell lint (and other tools) which language is the default language
in your res/values/ folder by specifying tools:locale="languageCode" for
the root <resources> element in your resource file. (The tools prefix
refers to the namespace declaration http://schemas.android.com/tools.)
Source: https://android.googlesource.com/platform/tools/base/+/master/lint/libs/lint-checks/src/main/java/com/android/tools/lint/checks/TranslationDetector.java#88
Add the locale specification to your default language file, and you shouldn't get that error for en-rUS, but will still be informed of any other missing translations.
This seems to not answered yet, so I show you one solution:
In your DEFAULT xml file, you can define strings, that don't need translations like following:
<string name="developer" translatable="false">Developer Name</string>
This string does not need to be translated and lint will not complain about it either...
This is a Swiss knife answer, so you can ignore the missing translations message depending on which situation you are:
Ignore all MissingTranslation message:
Edit your build.gradle file:
android {
lintOptions{
disable 'MissingTranslation'
}
}
Ignore all MissingTranslation messages in a concrete resources.xml file:
<?xml version="1.0" encoding="utf-8"?>
<resources
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="MissingTranslation">
<!-- your strings here; no need now for the translatable attribute -->
</resources>
Ignore MissingTranslation message for only one string:
<string name="developer" translatable="false">Developer Name</string>
If you are using Eclipse, please look at the toolbar buttons of the Lint warnings view. One of them is called "Ignore in file". This should help, but only if Lint assigns the error to your "US" file. That button simply modifies the lint.xml file in your project, so you can investigate (and undo) that easily.
More details about that file specific suppression are at http://tools.android.com/tips/lint/suppressing-lint-warnings
For the lint configuration file lint.xml:
<issue id="MissingTranslation" severity="ignore" />
If case of using gradle 7 :
lint {
disable("MissingTranslation")
}

Setting android:versionName as reference to string resource leads to NullPointerException under the emulator

I'm trying to set the android:versionName in my android manifest as a reference to string resource stored in external resource file.
Below is an excerpt from my AndroidManifest.xml:
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.toycorporation"
android:versionCode="#integer/version_code"
android:versionName="#string/version_name"
>
and the content of build.xml file located under res/values disrectory of my project:
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<item type="string" name="build_date">03/15/2012</item>
<item type="integer" name="version_code">315281</item>
<item type="string" name="version_name">3.15.28.1</item>
</resources>
Later I attempt to retrieve the version number to display it on the About screen of my application.
PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(),0);
Log.d("PackageInfo", "Version name: " + String.valueOf(packageInfo.versionName));
Problem description:
When I build the application and automatically install it on my HTC device everything works perfect. Version name gets passed by reference and on the About screen I get version name value logged in the logcat.
But when I attempt to build the application and launch it on the emulator I get null instead of the version name value.
I have already tried to build and install the app to emulator using Eclipse and IDEA.
So it seems the issue is not related to IDE.
UPDATE:
One additional thing appeared which doesn't work with such use of versionName and versionCode. Application can not be deployed to the Google Play. The following error appears:
The file is invalid: ERROR getting 'android:versionCode' attribute:
attribute is not an integer value
I think there is a mix of issues with this approach / how you are using it.
1.) if you can compile and upload the APK to the android market and the correct version number and name is used then you are able to use resource references for the android:versionCode="#integer/version_code" android:versionName="#string/version_name"
If you can't then you shouldn't be using rerences.
2.) If you are going to take this approach, why then try to retrieve them from the packageinfo over using getResources().getString(R.string.version_name)?
All in all I don't see much of an advantage of this approach beyond being able to swap out a resources file by a build box. In which case you may need to for the latter approach to populate your about screen.
You can set versionName in manifest as a reference to string resource, but not versionCode.
This should work. in dimensions.xml add the following.
<resources>
<item name="version_number" format="float" type="dimen">2.8</item>
<item name="version_code" format="integer" type="dimen">8</item>
</resources>
In your manifest add the following.
android:versionCode="#dimen/version_code"
android:versionName="#dimen/version_number"

Categories

Resources