Gradle combined flavors doesn't work - android

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

Related

Access a variable in Java or string.xml from Gradle

I have a value for a String in String.xml
<string name="id">4</string>
and I have a class which contains a variable
public static int Id=1;
Now what I need is I want to get either of these two values in the gradle, which will check a condition and based on the condition it will rename my app. Below given is the part of the gradle code
def identifier //here i need to get value from the java or xml
switch(identifier)
{
case 1:
temp="ApplicationNewName";break;
}
newName=newName.replace("-release",temp);
output.output.File=new File(output.outputFile.parent,newName);
My question is that, Can i access the variables initialised in the java file or string xml in gradle file ?
You're approaching this problem backwards, Gradle gives you the ability to set those variables within the script itself and then you can further access those variables throughout your Android code. Here's a relevant answer for how you can set build configuration variables: https://stackoverflow.com/a/17201265/2168085
It also sounds like you are trying to build different apps from a single code base, or build variations of those apps. If that's the case then you should really look into build flavors to solve this problem. Essentially a build flavor allows you build different apps from a single main code base and apply variations or new functionality to the different flavors. This can be as basic as having a free and paid version of an app or a full white label code base where you can build very different apps from the same master code base. In Android these are more commonly known as build variants and the developer documentation gives plenty of good information on how to get started: https://developer.android.com/studio/build/build-variants.html

ApplicationId conditioned by build type and flavour dimension

I have an application which has 2 flavour dimensions. First dimension, lets call it "brand" has two types:
"strawberry", "cyan"
Both have different applicationIds, but we can focus only on one of those. Lets say "cyan" has applicationId "com.cyan.app".
The second flavour dimension is called say "environment". It has two values:
"prod", "test".
I also have two build types:
"debug", "release"
Now what I'm interested in, is how can I go about configuring the gradle script such that whenever I'm building debug versions there will be applicationIdSuffix which will contain both "debug" string and environment name string. So in the above example it would be:
com.cyan.app.debug.prod and com.cyan.app.debug.test
But if I build release version of an app I want to leave the main applicationId, so com.cyan.app, no matter the environment flavour.
Is there any way I can achieve that with gradle and android gradle plugin?
Ok, I've sit down during the weekend and was able to achieve that (and more). Sharing here so that others can benefit who would like to achieve the same thing as I posted in the question.
So first of all we have to attach ourselves to the applicationVariants.all task like so:
applicationVariants.all { variant ->
//We tweak the package name and application name depending on the variants (so that we can have multiple applications installed on the phone, depending on the
tweakPackageName(variant);
replaceInManifest(variant, 'android:label=\"#string/app_name\"', 'android:label=\"#string/
}
I've separated the logic to other methods so that the code is not clogged. The tweakPackageName method looks pretty simple (as it turned out):
/**
* Method that alters the package name in order to have many different variants of application installed simultanously on a device.
*/
ext.tweakPackageName = { variant ->
def envFlavor = getFlavorOfDimension(variant, flavorDimEnvironmentName);
variant.mergedFlavor.applicationId = variant.mergedFlavor.applicationId + ".${envFlavor.name.toLowerCase()}";
}
getFlavorOfDimension is a simple method to get the flavor of particular dimension I'm interested in (not a biggie so I won't spam with this code here). When we get the flavor we add it to the package name of the mergedFlavor object and we're done.
I also managed to not only change the package name but also to dynamically change the application launcher name, but there are plenty of solutions of that on StackOverflow so I won't be redundant here. All in all the solution to alter the package name works. Hopefully it will help someone like it helped me.

Android extend default locale

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.

Setting resourceDir for Robolectric Test Cases

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

Android - Multiple .apk file from single code base

I had developed 3 applications in android where the major functionalities are the same but the UI looks different. Images and the background color of the screens are different.
NOw, i want to create a single code base from which i can generate multiple .apk files for the 3 apps.
I tried creating 3 different packages for src folder for the 3 apps. But i dont know how to set the res folder for these apps.
Need pointers on creating a single code base from which we can generate multiple .apk files which includes only the respective src and res folders.
Use an Android Library Project that contains all your common code.
Create separate Android projects that reference the Library Project (you will need to copy your Manifest into each of these and make sure all components are declared with their full Java package name).
Put any resources specific to each app (drawables, colors etc) into the individual project resource folders and they will override similarly named resources in the library project at build time.
i think the best option is to use ant, you'll need to add an ant target for each build and change the resource folder.
if you use the generated build.xml, the res folder is defined like this
<property name="resource.absolute.dir" location="res" /> so you'll want to override that
Can't you put all of your common code into a library project and then just reference that project from each of the 3 unique projects that each contain the relevant resources.
Update: This answer is now obsolete when using the Gradle build system.
Why don't you use a single application, that does three different things based on SharedPreferences values set by the user, or from context at install time. If you really want to separate, you can have three different activities, and you decide which one to launch from a silent main Activity that redirects to either of the different ones.
An alternative is to have a unique activity that inflates itself dynamically from 3 different layouts at onCreate time.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (...custom check for layout... equals(layout1)) {
setContentView(R.layout.main_layout1);
} else if (... equals(layout2)) {
setContentView(R.layout.main_layout2);
} else if (... equals(layout3)) {
setContentView(R.layout.main_layout3);
} else {
throw new IllegalStateException("Unknown layout!");
}
... your onCreate stuff....
}
It will make code maintenance easier (only one code source to modify, only one version-list and changeset to maintain)
Check here:
How to use SharedPreferences in Android to store, fetch and edit values
I would suggest using Gradle flavors.
It seems to explain all the basics really well. I just finished converting to Gradle today, and it works great. Custom app icons, names, and strings, etc.
As the website explains, part of the purpose behind this design was to make it more dynamic and more easily allow multiple APKs to be created with essentially the same code, which sounds similar what you're doing.
Also see a recent question I had, referring to your project structure and using custom code for each app.

Categories

Resources