Android maven plugin: renameManifestPackage results in Resources$NotFoundException - android

I encountered the following problem:
The app I implemented includes another project as a dependency (of type aar). Both projects share the same parent pom. The dependency includes resources, which the app is using. To access the resources within the library project, the resource id is fetched by calling context.getResources().getIdentifier(resourceKey, resourceType, packageName). I get the package name by calling getPackageName() on the given context object.
Before changing the package names of the projects by using
<renameManifestPackage>com.example.newpackagename</renameManifestPackage>
accessing the library resources worked fine. But after renaming the package name of the app I get a android.content.res.Resources$NotFoundException because the getIdentifier() call still expects the old package name of the app and calling getPackageName() returns the new one (as expected).
Now I wonder if I'm missing something or if this a bug in the android maven plugin? https://github.com/simpligility/android-maven-plugin

The answer is: I missed something. I opened a ticket regarding this problem at the project site (https://github.com/simpligility/android-maven-plugin/issues/736). It turned out that what I've seen as a problem is expected behavior of the renameManifestPackage configuration, since renaming not only the manifest package but also the resources is out of scope for this configuration.
There is, however, a not too ugly workaround for this:
Instead of retrieving the package name from the Context object, it is possible to retrieve it from the Resources object. Here comes the part where it gets a bit ugly: A resource with the single purpose of retrieving the package name needs to be added since other resources are usually subjects to change:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- The only purpose of this resource is to retrieve the resource package name -->
<item name="used_for_package_name_retrieval" type="id"/>
</resources>
Now you can retrieve the resource package name as follows:
Resources resources = context.getResources();
String packageName = resources.getResourcePackageName(R.id.used_for_package_name_retrieval);
Credit goes to: http://www.piwai.info/renaming-android-manifest-package/

Related

A string resource from an Android lib overrides a resource from the app with the same name

I created a simple Android project out of my curiosity. It contains two modules: app and lib. Each module has its own package name. I created one string resource in the lib module and one string resource in the app module. Like this:
<string name="my_str">my_str_from_lib</string>
<string name="my_str">my_str_from_app</string>
Then I set the texts to two TextViews in the app module:
fromLib.text = resources.getString(ru.maksim.sample.lib1.R.string.my_str) // here I expected to see the string from the lib.
fromApp.text = resources.getString(R.string.my_str)
In both cases it was my_str_from_app
I ran Lint and thought it would detect the fact of resource overriding. But it didn't.
Is there a chance to detect this situation? Not necessarily with Lint. Other tools suit me too.
Well you can do a global search in your root folder. Find all instances of my_str and make sure its only the string.xml in your app that uses it as name.
The answer here is a script that parses a resulting XML to which all the string from the main app module and all its libraries are merged and finds all the duplicates.

Package name changing improperly

I changed my package name using the method of refractor > rename after deselecting 'compact empty middle package' in project window as shown in this video :
https://www.youtube.com/watch?v=A-rITYZQj0A
Now my project window shows the changed name, each of my java files show changed name, even my manifest also shows the updated name...but when I log getPackageName() it still returns the old name. Am I missing something here ?
Update 1:
When trying to access my raw resources using uri, even then they are being accessed only by old package name...
Found the solution : It appears that changing package name in the described way does not take effect as the appId defined in build.gradle file has precedence over manifest file. There is an issue registered at :
https://code.google.com/p/android/issues/detail?id=109072
as of now the guys at google doesn't consider it a serious issue...can't blame them...

List available Android resource packages at runtime?

Resources.getIdentifier(String,String,String) requires the resource package. Unfortunately, if the APK was built with aapt's --rename-manifest-package option, the resource package won't be the same as the package returned from Context.getPackageName(). For instance, if AndroidManifest.xml has the following:
<manifest package="foo.bar" ...>
...
</manifest>
but aapt is run with --rename-manifest-package foo.bar.baz, then the APK's resources will have the package name foo.bar while Context.getPackageName() will return foo.bar.baz. Thus, calls to Resources.getIdentifier(String,String,String) will return 0 whenever the package name from Context.getPackageName() is used.
How can I get a list of the available resource packages in the APK so I can search them for my resource identifier?
I don't believe there is a method to list the package identifiers in Resources, but you can always use getResourceTypeName() with a known R value to get the package name. Something like:
String packageName = res.getResourcePackageName(R.drawable.ic_launcher);
res.getIdentifier("name", "type", packageName);
I realize it's not ideal since it requires you to pass a known resource ID first, but it may be your only option.
See https://groups.google.com/forum/?fromgroups=#!topic/adt-dev/cqdjG2TuM-I
from Xavier Ducrohet:
They make the assumption that the package name of the app is the same
as the R class. This really is not correct. While the previous build
system somewhat implied this, aapt always had the feature to generate
the R class in a different package.
Thinking about it there really is no current way to query the app for
the package of the R class. It'd have to be provided to the library.
Basically, there is no way to do it. The package name would have to be passed to the library explicitly.
You can automate passing the package name by using a dummy R file:
It's easy to fix though, by retrieving the package name of another
resource with Resources.getResourcePackageName().
Let's create a resource id dedicated to that purpose, for example in
res/values/ids.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<item name="used_for_package_name_retrieval" type="id"/>
</resources>
And now we get the right package:
Resources res = context.getResources();
String packageName = res.getResourcePackageName(R.id.used_for_package_name_retrieval);
int id = res.getIdentifier("some_drawable", "drawable", packageName);

No resource identifier found for

When I try to refactor an app, I get hundreds of "No resource identifier found for (...)" Errors "in package com.app"
How can I solve this Problem?
I already tried to replace the values to the new package Name but the error remains the same.
The Errors happen at such code parts:
<com.example.app
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:latin="http://schemas.android.com/apk/res/com.fa.ime"
android:id="#+id/LatinkeyboardBaseView"
android:layout_alignParentBottom="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="#dimen/keyboard_bottom_padding"
android:background="#drawable/keyboard_dark_background"
android:textStyle="bold"
latin:keyBackground="#drawable/btn_keyboard_key_gingerbread"
latin:keyTextStyle="bold"
/>
R class, used to access resources in android, linked to use package name from Android.manifest. Replace in all imports of R class old package name for new package name. Unfortunately you only can use standard text search in this case.
As far as i know, only this class uses package name from manifest, so other imports should be fine.
I don't use Android support package, but if you using it, in every layout associated with activity, there can be parameter named tools:context which include reference to activity. If you changed package name of app, this also could be a source of your problems.

Cannot override library's xml resource with png resource in application?

I have an Android library MyLib containing everything I need for my app (targeting Android 2.2). This library has an XML resource:
drawable/main_background.xml
In my Application MyApp project I reference MyLib. Here I want to override specific resources (i.e. branding). So I added a background image in MyApp:
drawable/main_background.png
Eclipse keeps giving me this error:
[com.mycom.mylib.myapp] res\drawable\main_background.xml:0: error: Resource entry main_background is already defined.
[com.mycom.mylib.myapp] res\drawable\main_background.png:0: Originally defined here.
How can I override the resource in the library project?
You cannot simply override resource ID (it's the resource ID you are overriding, not the actual file) with a file with different extension in Android SDK. However, you can do the trick by putting in your project xml file with the same name (main_background.xml) and fill it in a proper way to display your new file (main_background.png), which you need to rename earlier. All syntax you need is descibed here:
http://developer.android.com/guide/topics/resources/drawable-resource.html
, in your case it could be simply (assuming you put this in your non-library project as main_background.xml, and you have your new png as main_background_new.png):
<?xml version="1.0" encoding="utf-8"?>
<bitmap
xmlns:android="http://schemas.android.com/apk/res/android"
android:src="#drawable/main_background_new" />
With above solution, you could refer to #drawable/main_background from your project and it should use your file included with that project, instead of a library one.
[com.mycom.mylib.myapp] res\drawable\main_background.xml:0: error: Resource entry main_background is already defined.
[com.mycom.mylib.myapp] res\drawable\main_background.png:0: Originally defined here.
I don't believe you can have the same file name even with different extensions. Try naming the png something else.
Now, i've not used overriding, So this seems odd as you'd expect this to be how you override the asset. However i think you've either got the two assets in your lib named the same. And that in your project it might be ok to have an asset with the same name. I would however check that its ok to have different types. XML is different than png, and if you access the asset from code you could get type errors.
Let me clarify the above point. I understand that a library project can have an item with the same Resource ID as an item in your application.
However the error above suggests that both main_background.png and main_background.xml are in the same project ([com.mycom.mylib.myapp]) which i don't believe is correct.
Further reading
This page describes the various types of project including the library project http://developer.android.com/tools/projects/index.html
Now i don't know where i got the impression from but having looked again it simply doesn't state anywhere that you can override a resource by using the same resource name. God knows why i thought that was a feature.
So no, the same rule applies as far as i can tell, that resources have to be named uniquely even across library projects, otherwise the generated resource ids will conflict. (The error your getting)
What is explained is how resource conflicts are managed.
Resource conflicts Since the tools merge the resources of a library
project with those of a dependent application project, a given
resource ID might be defined in both projects. In this case, the tools
select the resource from the application, or the library with highest
priority, and discard the other resource. As you develop your
applications, be aware that common resource IDs are likely to be
defined in more than one project and will be merged, with the resource
from the application or highest-priority library taking precedence.
The system will use the resource with the highest priority, discarding everything else. Whats odd, is that you would think that a compile error wouldn't occur as the compiler should be discarding the resource. This makes me believe that the original poster had the similarly named assets in the same project, and not across the lib and project.
I haven't read anywhere that this is actually an intended feature. Got any links to say otherwise? (comment them)
So one 'solution' to this problem, which I do not consider to be an answer is the following:
Define an XML document in the library in question (we'll call it bunny.xml), and have it refer to another xml of a similar name (bunny_drawn.xml) with the actual content to be displayed.
Then, in the target project, override bunny.xml with another and use it to refer to an image with a different name instead - bunny_image.png
This does not however solve the problem, firstly because we aren't technically overriding a png with an xml (although the effect is somewhat close to that). Secondly because one of the key features of overriding resources is they are overridden, i.e. they are NOT compiled into the APK:
the tools ensure that the resource declared in the application gets
priority and that the resource in the library project is not compiled
into the application .apk
But the bunny_drawn.xml will still be compiled in! We can sort-of overcome the second point, by not only defining the image to be replaced in the target APP, but also replacing the old target bunny_drawn.xml with a blank xml. (or, as Fenix pointed out, you can have the contents of bunny_drawn.xml inside bunny.xml in the first case - the fact still remains that the resource ID can't be replaced...)
So my final conclusion is that this need to be submitted as a bug in the Developer Tools.

Categories

Resources