I do an application in two versions: premium and free. Now for me the functional of premium version works after verification of:
if (isPremiumVersion){
//to do premium fuctions
}.
But I do not think that it is good tone. How is it possible to divide these two versions, that they were independent of each other? Only at the start of application to do verification, and then already, for example, to start the certain manifest file with a certain package, and classes. Unfortunately, does not turn out to find material, how more correct to do it.
What you need is Product flavors.
You can define them in build.gradle:
android {
....
productFlavors {
free {
applicationId 'com.myapp.free'
}
premium {
applicationId 'com.myapp.premium'
}
}
}
For each product flavor you can create it's own source set by creating directory with name of flavor in app src directory so your app structure will be like:
src/
main/
free/
premium/
You can add customized AndroidManifest.xml, resources and sources in flavor source sets and they will be merged with main source set.
You should carefully read official documentation at link I mentioned above. There much more possibilities and details then I described here.
Related
I have two applications: Application Module A and Application Module B. They both use Library Module X.
Inside Library Module X I have some different behaviors depending of which app is using the library. I thougth about three alternatives to anchieve that.
1º Hardcoded mentioning the applications. someClass would be injected by the application or just check the package. (The worst one I think):
if (someClass.isApplicationA()) {
doThis()
} else {
doThat()
}
2º Hardcoded mentioning what is about to be done. someClass would be injected by the application. (I don't like it to much either):
if (someClass.shouldDoThis()) {
doThis()
} else {
doThat()
}
3º Using flavors. I would define a flavor A for Application Module A and a flavor B for Application Module B. In Library Module X I would define both flavors. So I would put the custom code in some specific classes that have different versions for each flavor.
customClassByFlavor.justDoIt()
Everywhere I only see flavors been used for a single application. Is this a correct use of it?
The elegant way to achieve this is
Ask the app to specify a identifier / key in their manifest
Ask the app to specify a variable in their build.gradle file
defaultConfig {
resValue "string", "identifier", "identifierConstant"
}
Use the variable in you app, like you acesss a string constant
context.getString(R.string.identifier);
Pick the package name of app from default applicationId in build.gradle file
defaultConfig {
applicationId "com.google.example"
}
productFlavors {
India {
}
USA {
}
}
Lets take 2 product flavours for an example
1. India
2. USA
total number of build variants will be 4
1. IndiaDebug
2. IndiaRelease
3. USADebug
4. USARelease
Which files are common for all flavours and which files are flavour specific as well as debug and release specific ?
If localization is supported and if english is common language for India and USA then each build will have separate english file or common file ?
Product Flavour is a awesome solution to build different varieties of the same application with individual features.
Specific Files
Say like , one of your Activity will have different functionality and UI, then you can avoid keeping that Activity in common package and move to respective flavour. Each flavour can have separate java and res folder along with Manifest (which is not mandatory, Studio take care of itself). It is here your specific Activity's java file and xml file should be placed.
Example : Login Screen will have different UI and features in each flavour
Now during runtime as well as compile time, Android Studio switches between the packages and picks suitable files. This is done through Build Variant feature
Common Files
So coming to common files which is applicable is all the flavours, let it be in main/java and main/res itself.
Ideally depending on your flavour numbers, bundle.gradle will look similar to this.
productFlavors {
student {
applicationId "com.abc.student"
}
staff {
applicationId "com.abc.staff"
}
tempstaff {
applicationId "com.abc.tempstaff"
}
}
sourceSets {
tempstaff {
manifest.srcFile 'src/tempstaff/AndroidManifest.xml'
}
student{
manifest.srcFile 'src/student/AndroidManifest.xml'
}
staff {
manifest.srcFile 'src/staff/AndroidManifest.xml'
}
}
Now to conclude the answer, files which are common throughout the
application will remain in the main package. Specific files
applicable to separate flavour will go in that flavour. This means
flavours can have extra Activity/Features that are not at all a part
of others including main also
Go through this link for more information.
As per need i need to manage one project for different clients in which i usually need to change application icon, app name and client logo. what is the efficient way to handle this??
I have read about properties file in the Android but that does provide option to change application icon and name.. it there any why to handle this.
To achieve this you will to have use flavour in your project, if you are using Android studio add the following code in your build.gradle file.
productFlavors {
flavor1 {
applicationId "com.app.client1"
}
flavor2 {
applicationId "com.app.client2"
}
}
Then create directory structure like
flavor1>res>drawable-XXX>ic_launcher.png (app icon for client1)
flavor2>res>drawable-XXX>ic_launcher.png (app icon for client2)
For more you can refer to this blog http://www.pcsalt.com/android/product-flavors-android/
You can create Multiple flavor for multiple vendors like this:
Here is a syntax for gradle
productFlavors {
flavor1 {
packageName 'com.android.studio.test.foobar'
}
}
You can also put variable to make changes in app according to flavor
I am endeavouring to migrate an Android App from Eclipse to Android Studio. The App naturally has 3 flavour dimension something along the line of:
flavorDimensions("skin", "cost", "market")
productFlavors {
skin1 {
flavorDimension "skin"
}
skin2 {
flavorDimension "skin"
}
free {
flavorDimension "cost"
}
paid {
flavorDimension "cost"
}
google {
flavorDimension "market"
}
samsung {
flavorDimension "market"
}
amazon {
flavorDimension "market"
}
With this I have three somewhat related problems that I cannot seem to find a clear solution to.
First issue is that the "applicationId" is dependent on 2 of the 3 dimensions, skin and cost. From the example above if I build skin1PaidGoogle I would have "com.example.skin1" if I build skin2FreeAmazon I would need "com.example.skin2_free". This is a live app so there is no opportunity to change here. How can this be achieved.
Second issue is the need for custom src/res sets. The default gives me folders for each flavour and for all combination of ALL flavours. So I get folders for "skin1", "skin2", "free", "Google" etc and I get folders for "skin1FreeGoogle" and "skin1PaidAmazon" etc. I am aware I also get build type variants. I also need folders like "skin1Free" "freeAmazon" "FreeGoogle". I only need a small subset of the myriad of possibilities here. How can these additional folders be added as appropriate to the srcSets? I am aware of the priority order which affects merging but I can manage this if I can just add the folders.
Third issue is to do with dependencies. I can have "compile" lines and I can have "freeCompile" lines but I need to also have "freeAmazonCompile" type lines.
Without these capabilities it seems to me I will either have to make many compromises and have many duplicated srcSets so any help much appreciated.
Our application has a free and a paid version. We also make branded-versions, which means that the application vary in two dimensions.
Four versions could be:
The App, Nike ed. free
The APP, Nike ed. paid
The App, Adidas ed. paid
The App, Adidas ed. free
My solution now is to have two build-types, paid and free:
buildTypes {
paid {
packageNameSuffix ".paid"
}
free {
packageNameSuffix ".free"
}
}
And two build flavors:
productFlavors{
nike{
packageName "com.example.theapp.nike"
}
adidas{
packageName "com.example.theapp.adidas"
}
}
Every free-version of the app make us of a content-provider, a content provider which is specific per flavor-build type combination. The problem is that I don't understand where to put a source file based on build variant. Source files put into /src/nike or /src/free will be picked up depending on build type or flavor. But how about source files that are depending on the build variant (the combination of type and flavor)?
You can create a new folder under src for every build or flavor that you have. i.e: 'free', 'paid', 'nike', 'adidas'.
The files that you put in any of these folders gets picked up when building depending on the type and build both.
According to Gradle Plugin User Guide on Android Tools Project Site:
Similar to Build Types, Product Flavors also contribute code and
resources through their own sourceSets.
and
The following rules are used when dealing with all the sourcesets used
to build a single APK:
All source code (src/*/java) are used together as multiple folders generating a single output.
Manifests are all merged together into a single manifest. This allows Product Flavors to have different components and/or
permissions, similarly to Build Types.
All resources (Android res and assets) are used using overlay priority where the Build Type overrides the Product Flavor, which
overrides the main sourceSet.
Each Build Variant generates its own R class (or other generated source code) from the resources. Nothing is shared between
variants.
meaning that your java files for the buildType "free" will overwrite the ones for your flavors "nike" if they have the same name.
But if you're adding something to a manifest, according to the second point in the list above the final manifest will be a merge of all of the manifests.
If you need more customization you can put your files in your build variant's folder "src/freeNike/".
I had similar problem with build types overriding flavors due to the overlay rules.
I ended up redirecting the build type source sets into different folders depending on which flavor was built.
android.applicationVariants.all { variant ->
switch (variant.name) {
case "FreeNike":
variant.mergeResources.doFirst {
android.sourceSets.free.setRoot("src/freeNike")
}
break;
case "FreeAdidas":
variant.mergeResources.doFirst {
android.sourceSets.free.setRoot("src/freeAdidas")
}
break;
case "PaidNike":
variant.mergeResources.doFirst {
android.sourceSets.paid.setRoot("src/paidNike")
}
break;
case "PaidAdidas":
variant.mergeResources.doFirst {
android.sourceSets.paid.setRoot("src/paidAdidas")
}
break;
}
}
You are of course free to use a different folder structure. See example here: Folder naming convention for gradle build variants
Have a look at newest Gradle plugin it now allows to have variant specific resources
http://tools.android.com/tech-docs/new-build-system
And here You have example of usage
https://android.googlesource.com/platform/tools/build/+/master/tests/overlay3/
Have you tried to put the srcDir in the sourceSets ?
Like so:
sourceSets {
main {
java {
srcDirs 'src/java'
}
}
}
That should output a javaResources with two source codes, nike and adidas.