I have a project with about 30 product flavors. Some of these product flavors need to share code, without sharing it with most product flavors. Can I assign code to a flavor group?
1) Do you know how to create folders for a particular product flavor?
You can create a folder with sources or resources that will be used for a particular combination of flavors too. https://developer.android.com/studio/build/build-variants.html#sourcesets
For example, we have flavors: "beta", "prod" in one dimension and "newApi", "oldApi" in another. We use one class implementation for all the flavor combinations except when it is beta with new api. So we found how gradle names this buidle variant (betaNewApi), created folder project/app/src/betaNewApi and put our class there, saving project structure for packages. As a result, classes that need this particular class take usual one or this particular only in this combination of flavors.
2) If you need to share not a whole class but only some small part of code, you can use runtime-checks for flavors:
if (BuildConfig.FLAVOR_releaseType.equals("prod"))
&& BuildConfig.FLAVOR_apiLvl.equals("newApi")) {
// here is your shared code
}
We extracted constants like "prod" into our Application class and use them in such ways.
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
Using build variant in Android we can support different flavors.
I need to develop an application where I am supporting different clients. Each client needs are a little different.
However, the basic data, network call class etc are same for all clients.
How can I ensure partial code of my application remains same for all flavors?
This will help in maintaining one repository for all common classes.
You need to understand how build variant works.
Each client needs are a little different is a vague statement
Imagine you have an application which has different screen's for different countries. But major functionalities are the same.
Now using build variants you can make different flavors
1) For country one : This will have screens designed specific to country one
2) For country two : This will have screens designed specific to country two
3) Common part : All the common business logic can be put under your common package
While project is build, the common part is considered and specific flavor too becomes part of flavorXX.apk
productFlavors {
employee {
applicationId "com.myapp.employee"
}
driver {
applicationId "com.myapp.driver"
}
asset {
applicationId "com.myapp.asset"
}
vehicle {
applicationId "com.myapp.vehicle"
}
}
sourceSets {
asset {
manifest.srcFile 'src/asset/AndroidManifest.xml'
}
driver {
manifest.srcFile 'src/driver/AndroidManifest.xml'
}
employee {
manifest.srcFile 'src/employee/AndroidManifest.xml'
}
vehicle {
manifest.srcFile 'src/vehicle/AndroidManifest.xml'
}
}
In the above example , I am having different flavors of same application. Inorder to split accordingly you need to understand which part of your app goes into specific flavor and which can be kept common. Go through below links for more details.
Understanding Product Flavors reference link 1
Understanding Product Flavors reference link 2
Lets imagine the following case:
I'm building an application for cars, lets say VW. Now Skoda (belongs to the same group) wants the very same application but with different ressources files, and some checks need to be made into the code like. If VW, call this webservice, else if Skoda, call this other one.
I can't really answer to this question: "Is it the same application?"
Yes from the code point of view but no from the play store point of view...
How can I manage to have the same code base but with two different packages name?
I think I am in the good track reading this http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants but if you have any tricks, advice or help to share I would be glad to hear :)
I know this question has been asked, but I'm looking for a solution with gradle & Android Studio.
Tx
Hello you can use product flavor to define the package name for each new application as #stoke said
productFlavors {
app1 {
applicationId "com.example.package.app1"
buildConfigField "String", "API_URL", "\"https://www.myapi.com/apiv1/\""
}
app2 {
applicationId "com.example.package.app2"
buildConfigField "String", "API_URL","\"https://www.myapi.com/apiv2/\""
}
}
For defining different endpoints or url in your builds you can define build variable to use in your code.
Then you can access them like BuildConfig.API_URL in your java code.
For different resources for diferent flavors you need to define 2 directories that match the new flavors names.
Check this for file sctructure and resources.
The id of the application used by googles's play store is defined in the Build.gradle file :
like
productFlavors {
vw {
applicationId = "com.example.my.pkg.vw"
}
skoda {
applicationId = "com.example.my.pkg.skoda"
}
The ressources folder simply needs to be created under the new flavor's auto generated folder. see http://www.vogella.com/tutorials/AndroidStudioTooling/article.html#androidstudio_creatingresourcefolder for more info
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.
I am using product flavors for my app and I need different default activities for each product flavor. Since I can not override classes in main/java, I need to delete the default activity in this folder and copy a custom version of it to flavor1/java and flavor2/java.
Now my project does not compile, because it can not find the default activity. In the manifest in main/java I did not declare a default Activity. Only in the two flavors manifests. Any ideas how to solve this issue?