I'd like to use a different resource directory for one of my Robolectric test cases. In this case i'd like to use the release-variant resources.
The thing is I can't get this to work and I'm not seeing examples online of anyone using this config.
It still uses the debug resources (Im running gradle testDebug where 'Debug' is one of my buildTypes in Gradle). The directory i'm setting is correct relative to the directory where the manifest is. I've tried referencing the ref files in "build/intermediates/.." too. The configuration seems to have no effect at all.
#RunWith(RobolectricTestRunner.class)
#Config(resourceDir = "../../variant_resources/release/res")
..
#Test
public void testHowThingsAreUsingReleaseResources() {
..
}
Im using Robolectric 2.4-SNAPSHOT
Has anyone had had better luck using this Configuration? Is there an obvious mistake?
Qualified Resources
If the resource file is to vary based on the sub-folder, then it's possible to specify a qualifier for the resource. See the RoboElectric page on Qualified Resources.
The #Config attribute with the qualifiers parameter can be used to specify the qualifier for the resource.
For example, if there are resources:
values/strings.xml
values-en/strings.xml
values-en-port/strings.xml
... then the attribute #Config(qualifiers="en-port") would ensure that the values-en-port/strings.xml resource would be used.
Changing resource paths using a different RobolectricTestRunner
Another approach to load different resources (if this is only to apply to some tests) is to implement a different implementation of the RobolectricTestRunner class, that loads different resource paths. There's a good example of how to do this here:
https://stackoverflow.com/a/29223625/3063884
Related
I'm developing on Android and have some difficulty with Gradle's build logic.
I'm trying to have a set of resources and java files for a combined flavors.
I put them in a folder src/productFlavor1ProductFlavor2/
But when I compile the build variant productFlavor1ProductFlavor2DevDebug , it simply doesn't get anything from the productFlavor1ProductFlavor2 folder.
I tried pretty much everything...
From the syntax and order:
src/productFlavor1ProductFlavor2/
src/productFlavor1productFlavor2/
src/productFlavor1-productFlavor2/
src/productFlavor1/ProductFlavor2/
To trying to indicate the folder to gradle
android.applicationVariants.all { variant ->
if (variant.getProductFlavors().get(0).name.equals('productFlavor1')
&& variant.getProductFlavors().get(1).name.equals('productFlavor2'))
variant.sourceSets = 'src/productFlavor1ProductFlavor2'//read only... so doesn't work
}
Anyone knows why the combination of flavors indicated in https://developer.android.com/studio/build/ doesn't actually work....? Or if I'm missing somethine there...
To make this work you need to define multiple dimensions of flavors.
It is not allowed to combine the single flavor dimensions.
I don't think it is a good idea to put source code to multi-flavor folders anyway as you are getting too many combinations to take care of.
If I were on your place, I would treat every dimension separately instead ie:
have a separate folder with productFlavor1 & productFlavor2.
Check this out: flavors, overview of build system.
The priority order for the different folders:
1. build variant (fully qualified name, like debugFlavor1Flavor2/src)
1. build type (debug/src)
1. product flavor (if you have multiple dimensions they ordered in order of declaration)
1. main/src
I am currently working on an Android project with multiple source sets.
My question is concerned with string resources.
The majority of the string resources are in the main/res/values directory.
There is an alternative source set called foo which overrides some of the string resources in main/res/values. This works just fine, however there is an additional source set we can call foobar that is a slightly different version of foo.
Is there a way foobar can be configured to use the resources defined in foo/res/values instead of defaulting back to main/res/values? Despite the source sets both being slightly different, the resources between foo and foobar are to be identical so I'd only like to write them once.
Essentially in foobar if I try to get the string resource cat I want it to look in foo/res/values/string.xml as if I was making the resource reqeust in foo; and just like in foo; fallback to main/res/values if that resource isn't defined.
Is there a way that I can structure my project to have this behavior? I am limited in how much I can restructure the source sets within the project, so I understand that the problem I am presenting might go against some conventional practices.
The solution to my problem was to add the following to my application's build.gradle
android.sourceSets {
foobar.res.srcDirs = ['src/foo/res']
}
I have inherited an old android app, and the first thing I did, was change the build from Ant to gradle.
The app builds fine, but when I try to run the release target, gradle fails complaining about missing translations.
The folder structure of the resource folder is: (the default language, in the values folder is en-GB)
res/
values/
/file1.xml
/file2.xml
/file3.xml
/values-us/
/file2.xml (containing just the few lines that differ from /value/file2.xml
/values-dk/
file1.xml
file2.xml
file3.xml
So, basically the linter is correct, most of the files are missing in the values-us folder.
However, a single locale contains about 20 files, with around 100+ lines each, and the difference between the default and US is probably 5 lines total, it seems impractical to have to maintain all values for both locales.
To be clear, I absolutely want the release target to fail, when values-dk/ or values-de/ are missing translations, I's just like some way to mark the US locale as an extension of the default. Is this possible?
I think Lint found some strings that are not in res/values but in res/values-{language}. In this case, if the code tries to use one of those strings and the string selection falls to default one (phone is set to a language where you don't provide translations), the application will crash.
The error should tell you which string is not translated. I'd start by checking the languages defining it and make sure it's also in the default ones.
So it turns out this is actually pretty simple. All I had to do was rename the values-us/ folder to values-en-rUS/ and it works.
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.
My application depends on a library project.
The menu.xml file is within the application project.
All the java code is within the library project, including the menu handler code onOptionsItemSelected().
Is there a way to access the application resources from library project ? I'd like to write something like this, which is currently impossible, since menu items are not visible from the library:
if ( item.getItemId()==R.id.settings ) {
...
}
Yes you can if you know the package name of your library. See: Resources#getIdentifier
You can do:
getResources().getIdentifier("res_name", "res_type", "com.library.package");
ex:
R.id.settings would be:
getResources().getIdentifier("settings", "id", "com.library.package");
You should really just include a version of the menu.xml resource in your library project. If you want to have a different menu.xml in your application, you can do that and it will override the copy from the library project.
From the Library Projects docs:
In cases where a resource ID is defined in both the application and the library, 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. This gives your application the flexibility to either use or redefine any resource behaviors or values that are defined in any library.
I found #triad's solution with Resources.getIdentifier(String, String, String) to be somewhat error-prone:
the String-literal resource identifiers aren't checked by the IDE
multiple sequential String arguments to a single method are easy to use incorrectly.
I found this approach to work better for me:
String libString = context.getString(example.library.pkg.R.string.library_string)
Where the library's package is example.library.pkg.
The library's R class is resolved at compile-time, so your IDE will tell you if you referenced it correctly
Not importing the library's R class allows you to still use your own local R later,
and explicitly marking the external resource usages makes them easier to spot.