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);
Related
Are int value of R.id.view is always same?
I tried printed it in two devices and it was same.
I also changed name of id but still the value was same.
But will it stay the same in all scenarios?
For any particular app resource, the particular R class associated resource ID will be the same in all scenarios during runtime as this resource ID is generated by aapt during compile time.
From Android Documentation:
Once you provide a resource in your application, you can apply it by referencing its resource ID. All resource IDs are defined in your project's R class, which the aapt tool automatically generates. When your application is compiled, aapt generates the R class, which contains resource IDs for all the resources in your res/ directory.
Thus printing it in two devices will result the same int value, provided that the same apk is used. Also note that the resource id is final in the respective R subclass.
From this answer:
Note that aapt by default makes no attempt to keep these identifiers
the same between builds. Each time the resources change, they can all
get new identifiers. Each time they are built, a new R.java is created
with the current identifiers so your code gets the correct values.
Because of this, you must never persist resource identifiers anywhere
where they can be used across different builds of your app.
Any changes to the resource might make the resource get an new R class resource ID.
Based on the way in which the R class Resource ID are calculated, as described in that answer, I think since you only changed the name of the XML resource ID, and didn't change the type of the resource nor the placement of the respective View object declaration in the respective XML file, the same R class Resource ID is being calculated.
A View ID is generated during Compilation, so Yes the ID will be the same in each Device if the APK is the same. Pay attention that "different compilations could generate different IDs".
I have a project with multiple flavors, apple and banana. It references a file that is stored in the raw resource directory. I would prefer to avoid naming each one database.sqlite and instead keep the name relevant to the flavor, apple.sqlite and banana.sqlite. In my code, I have a line that reads as
getResources().openRawResource(R.raw.apple);
Is it possible to create an integer resource that could essentially link to the right id, or would I be better off making a class in each flavor that would have the link to it?
You can create dedicated source sets for build types, product flavors (such as apple and banana), and build variants. You can create resource aliases, to give a resource another identifier. You should be able to mash these up to get what you want.
I assume, from your question, that you have apple/res/raw/apple.sqlite and banana/res/raw/banana.sqlite in your project. If so, then:
Create apple/res/values/ids.xml, and in there have <item type="raw" name="whatever">#raw/apple</item>
Create banana/res/values/ids.xml, and in there have <item type="raw" name="whatever">#raw/banana</item>
Use R.raw.whatever to identify this resource in your code in main
(where you can replace whatever with, like, whatever)
Here, you are setting up a common alias (whatever) for the resource, pointing the flavor-specific definition of the alias to the flavor-specific resource.
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/
I am using getIdentifier to get the id of a raw resource by name. It is not working though, and I am certain to be using it correctly. Is there something that I am missing?
I have verified that the raw resources exist under the string I am giving it. I have also cleaned the project to make sure that R.java is correct.
id = ctx.getResources().getIdentifier("file_name", null , ctx.getPackageName());
Looks like the methods needs the type/ (or defType) param. Should be something like drawable or layout depending on the resource directory.
You can include it in the first String parameter :
id = ctx.getResources().getIdentifier("drawable/file_name", null , ctx.getPackageName());
or pass it as the second parameter :
id = ctx.getResources().getIdentifier("file_name", "drawable", ctx.getPackageName());
Also, be sure to exclude the file extension from the file name you're passing. If the methods still returns 0, check if file_name corresponds to an id somewhere in your R.java file.
Way late, but I think this issue is related to an incorrect application id.
It is configured in you app's module build.gradle file:
android{
defaultConfig {
applicationId "your application id goes here"
From what I have observered, It seems the packageName for the generated R file is base on the value of the packageName in the Manifest.xml file. However the context.GetPackageName seems to be returning the value of the configured applicationId. If they are the same, then there's no issue. If they are different than a call to resources.getIdentifier(…,..., ctx.getPackageName()) will fail to find the identifier.
I'm not sure that the above paragraph is totally correct. What I actually observed was that If I changed the applicationId to match name of the PackageName in the Manifest.xml file then the issue I had on not getting a resource identifier using the getIdentifer method went away. I have to admit, I was somewhat surprised that corrected my problem.
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.