set applicationIdSuffix depending on productFlavor - android

We have 2 productFlavors (testServer, liveServer) and 2 build types (debug, release).
Due to existing API keys, I have to append package names based on buildType + productFlavor.
For example something like:
buildTypes {
debug {
applicationIdSuffix '.dbg' + (testServer ? '.test' : '.live')
}
release {
applicationidSuffix '' + (testServer ? '.test')
}
}
is this possible? how?

productFlavors {
testServer {
applicationId = "com.example.my.pkg.test"
}
liveServer {
applicationId = "com.example.my.pkg.live"
}
}
buildTypes {
debug {
applicationIdSuffix ".debug"
}
}
For more information, take a look at the Android documentation regarding application ids.

Related

Declare variable into build.gradle that match the applicationId with flavors suffix

I don't figure out how can I set a resource value (resValue) in my build.gradle, depending on the build variant selection.
Here a bit of explanation.
I'm working with the Skype For Business SDK (hereafter referred to as Sfb) and during is implementation, it ask me to add a resource value named ENTERPRISE_AUTHENTICATOR_ACCOUNT_TYPE.
So I was looking in their application example (available here) and found that in build.gradle they have added as follow the corresponding value :
android {
...
defaultConfig {
applicationId "com.microsoft.office.sfb.sfbdemo"
...
resValue ("string", "ENTERPRISE_AUTHENTICATOR_ACCOUNT_TYPE", "${applicationId}"
}
...
}
This value then used in a SfbSDK class, checking if it match the application package name.
And here is my trouble, I work with different flavorDimensions as describe in my build.gradle below.
apply plugin: 'com.android.application'
...
android {
...
defaultConfig {
applicationId "com.tsp.test"
...
resValue ("string", "ENTERPRISE_AUTHENTICATOR_ACCOUNT_TYPE", "${applicationId}"
}
...
flavorDimensions("customer", "version")
productFlavors {
a {
dimension "customer"
applicationIdSuffix ".a"
}
b {
dimension "customer"
applicationIdSuffix ".b"
}
alpha {
dimension "version"
applicationIdSuffix ".alpha"
}
beta {
dimension "version"
applicationIdSuffix ".beta"
}
release {
dimension "version"
applicationIdSuffix ".release"
}
}
}
...
Depending on my build variant selection, this will generate me 6 different APK :
com.tsp.test.a.alpha ; com.tsp.test.a.beta ; com.tsp.test.a.release
com.tsp.test.b.alpha ; com.tsp.test.b.beta ; com.tsp.test.b.release
So when the match checking is does, my application crash with the message error
Caused by: java.lang.RuntimeException: ENTERPRISE_AUTHENTICATOR_ACCOUNT_TYPE string not set to applicationId
at com.microsoft.office.sfb.appsdk.Application.initialize(Application.java:110)
at com.microsoft.office.sfb.appsdk.Application.getInstance(Application.java:144)
at com.tsp.test.RootActivity.onCreate(RootActivity.java:89)
Of course, because com.tsp.test doesn't match com.tsp.test.a.alpha (or any other APK).
How can I achieve a dynamic resValue depending on the build variant selected that match the right application package name ?
EDIT :
To explain a bit more. First I choose the Build Variants as follow :
Customer : A
Version : Alpha
Then, in my RootActivity#onCreate() (my launcher activity), I start to configure the SfbSDK with an application instance depending on the SfbSDK :
this.mApplication = com.microsoft.office.sfb.appsdk.Application.getInstance(this.getApplication().getApplicationContext());
Somewhere in getInstance() method, the SfbSDK do an equals() between the context.getPackageName() and context.getString(string.ENTERPRISE_AUTHENTICATOR_ACCOUNT_TYPE);
So, for debug, in my RootActivity#onCreate() I just wrote this two lines
String whatIWant = this.getPackageName(); // give me *com.tsp.test.a.alpha*
String whatIGet = this.getString(R.string.ENTERPRISE_AUTHENTICATOR_ACCOUNT_TYPE); // give me *com.tsp.test*
This doesn't match ! So in SfbSDK the condition wasn't passed.
Well, thanks to Radesh and this link he provided to me, I've found my solution.
I removed resValue from the defaultConfig block then I added a new block in the android plugin task, that create the resValue for each variant.
apply plugin: 'com.android.application'
...
android {
...
defaultConfig {
applicationId "com.tsp.test"
...
}
...
flavorDimensions("customer", "version")
productFlavors {
a {
dimension "customer"
applicationIdSuffix ".a"
}
b {
dimension "customer"
applicationIdSuffix ".b"
}
alpha {
dimension "version"
applicationIdSuffix ".alpha"
}
beta {
dimension "version"
applicationIdSuffix ".beta"
}
release {
dimension "version"
applicationIdSuffix ".release"
}
}
...
applicationVariants.all { variant ->
variant.resValue "string", "ENTERPRISE_AUTHENTICATOR_ACCOUNT_TYPE", "\"${applicationId}\""
}
}
...
This generate correctly the resValue with the package name of the selected variant.
For variant customer A and version Alpha, I get resValue = com.tsp.test.a.alpha.
you must declear variable ENTERPRISE_AUTHENTICATOR_ACCOUNT_TYPE in gradle.properties like below
//default
org.gradle.jvmargs=-Xmx1536m
ENTERPRISE_AUTHENTICATOR_ACCOUNT_TYPE=xxx

How to configure manifestPlaceholders?

I have 2 flavors and 2 buildType. ApplicationId is a constant and other is variable;
I need cofigure manifestPlaceholders value for this logic:
value = applicationId + (currentFlavor.equals(flavor2) ? "c" : "") + (currentBuild.equals(buildType.debug) ? "dev" : "")
manifestPlaceholders = [pakackage:value]
That is, for flavor2 will be added the suffix "c" for the debug build will be added as the suffix "dev". It's possible?
If you want to have builds with different applicationIds based on flavor and build types
productFlavors {
flavor2 {
applicationIdSuffix ".c"
}
...
}
buildTypes {
debug {
applicationIdSuffix ".dev"
}
release{
}
}
These builds will be generated:
flavor2Debug: yourApplicationId.c.dev
flavor2Release: yourApplicationId.c
flavor1Debug: yourApplicationId.dev
flavor1Release: yourApplicationId

Mobile app clones from same codebase

I have an android app that I want customized for different clients, usually changed colors.
I could use flavors, but
The problem is that every app should have 2 stages (so, 2 apps for every client), 1 for QA and 1 for Prod and they use different rest-api urls, custom for each client.
What would be ideal for me is a way to nest flavors so I can define properties for each,but it's not supported. This will also allow me to modify some layouts for client_1 and use the rest from main, which I also need to do. Example:
productFlavors {
client_1 {
dev {
buildConfigField "String", "API_URL", "https://...."
}
prod {
buildConfigField "String", "API_URL", "https://...."
}
}
client_2 {
dev { //...
}
prod {
//...
}
}
}
Any idea how I can achieve that?
The other option would be to have a common library app and have different apps for different clients with their config, but that would make it more complex.
In my project i used , build types with product flavours. I will explain it here.
My project looks like this,
and add this lines in the gradle file,
buildTypes {
prod {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
dev {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
productFlavors {
client_1 {
applicationId "com.example.client_1"
versionCode 1
}
client_2 {
applicationId "com.example.client_2"
versionCode 1
}
}
When the app is based on more than one criteria, instead of creating a lot of flavors you can define flavor dimensions.
The flavor dimensions define the cartesian product that will be used to produce variants.
Example:
flavorDimensions("dimA", "dimB")
productFlavors {
row1 {
...
dimension = "dimA"
}
row2 {
...
dimension = "dimA"
}
row3 {
...
dimension = "dimA"
}
col1 {
...
dimension = "dimB"
}
col2 {
...
dimension = "dimB"
}
col3 {
...
dimension = "dimB"
}
}
This config will produce 18 (3*3*2) variants (if you have the 2 standard build types : debug and release).
The following build variants will be created:
row1-col1-debug
row1-col2-debug
row1-col3-debug
row1-col1-release
row1-col2-release
row1-col3-release
row2-col1-debug
row2-col2-debug
row2-col3-debug
row2-col1-release
row2-col2-release
row2-col3-release
row3-col1-debug
row3-col2-debug
row3-col3-debug
row3-col1-release
row3-col2-release
row3-col3-release

versionNameSuffix for product flavors

Is there any way to set different versionNameSuffix for various product flavors in a way it is possible to do this for build types?
The following code works for me:
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
verstionNameSuffix "-prod"
}
}
But when I want to set versionNameSuffix for product flavors like this:
productFlavors {
production {
versionNameSuffix "-prod"
}
development {
versionNameSuffix "-dev"
}
}
I get this error:
Error:(48, 0) Could not find method versionNameSuffix() for arguments [-dev] on ProductFlavor_Decorated{name=development, dimension=null, minSdkVersion=null, targetSdkVersion=null, renderscriptTargetApi=null, renderscriptSupportModeEnabled=null, renderscriptNdkModeEnabled=null, versionCode=null, versionName=null, applicationId=null, testApplicationId=null, testInstrumentationRunner=null, testInstrumentationRunnerArguments={}, testHandleProfiling=null, testFunctionalTest=null, signingConfig=null, resConfig=null, mBuildConfigFields={BASE_URL=com.android.builder.internal.ClassFieldImpl#1630a8db}, mResValues={}, mProguardFiles=[], mConsumerProguardFiles=[], mManifestPlaceholders={}} of type com.android.build.gradle.internal.dsl.ProductFlavor.
Is there any other way to set the versionNameSuffix for the product flavor?
productFlavors now support versionNameSuffix
From the android developer docs
https://developer.android.com/studio/build/build-variants#flavor-dimensions
android {
...
buildTypes {
debug {...}
release {...}
}
// Specifies the flavor dimensions you want to use. The order in which you
// list each dimension determines its priority, from highest to lowest,
// when Gradle merges variant sources and configurations. You must assign
// each product flavor you configure to one of the flavor dimensions.
flavorDimensions "api", "mode"
productFlavors {
demo {
// Assigns this product flavor to the "mode" flavor dimension.
dimension "mode"
...
}
full {
dimension "mode"
...
}
// Configurations in the "api" product flavors override those in "mode"
// flavors and the defaultConfig block. Gradle determines the priority
// between flavor dimensions based on the order in which they appear next
// to the flavorDimensions property above--the first dimension has a higher
// priority than the second, and so on.
minApi24 {
dimension "api"
minSdkVersion 24
// To ensure the target device receives the version of the app with
// the highest compatible API level, assign version codes in increasing
// value with API level. To learn more about assigning version codes to
// support app updates and uploading to Google Play, read Multiple APK Support
versionCode 30000 + android.defaultConfig.versionCode
versionNameSuffix "-minApi24"
...
}
minApi23 {
dimension "api"
minSdkVersion 23
versionCode 20000 + android.defaultConfig.versionCode
versionNameSuffix "-minApi23"
...
}
minApi21 {
dimension "api"
minSdkVersion 21
versionCode 10000 + android.defaultConfig.versionCode
versionNameSuffix "-minApi21"
...
}
}
}
...
You can also operate on productFlavors like this:
android.productFlavors.all { flavor ->
flavor.versionNameSuffix = "-${flavor.name}"
}
There is no direct way of doing so. Currently, com.android.application gradle-plugin does not support any DSL for productFlavors to have versionNameSuffix.
If you want to do this, you have to create two methods.
import java.util.regex.Matcher
import java.util.regex.Pattern
def getCurrentVersionSuffix() {
def currentFlavor = getCurrentFlavor()
if (currentFlavor.equals("prod")) {
return "-prod"
} else if (currentFlavor.equals("uat")) {
return "-uat"
} else if (currentFlavor.equals("dev")) {
return "-dev"
}
}
def getCurrentFlavor() {
String taskRequestName = getGradle().getStartParameter().getTaskRequests().toString()
Pattern pattern;
if (taskRequestName.contains("assemble"))
pattern = Pattern.compile("assemble(\\w+)(Release|Debug)")
else
pattern = Pattern.compile("generate(\\w+)(Release|Debug)")
Matcher matcher = pattern.matcher(taskRequestName)
if (matcher.find()) {
return matcher.group(1).toLowerCase()
} else {
return "";
}
}
and update the buildTypes DSL
buildTypes {
debug {
versionNameSuffix getCurrentVersionSuffix()
}
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
versionNameSuffix getCurrentVersionSuffix()
}
}
This is the only way to achieve right now. May be in future, they could provide some DSL or something.
I have written a blog on this (http://www.pcsalt.com/android/product-flavors-android/) and the code is pushed on GitHub (https://github.com/krrishnaaaa/product-flavours/blob/master/app/build.gradle).

Get gradle build type in product flavor

I need to create different app names depending on the product flavour used.
While this was easy by simply setting a string resource, I can no longer do that because when the app is uploaded to hockeyapp the app name is set as '#string/app_name' instead of the value of app_name.
I have made some progress by setting the label in the manifest to be '${applicationName}' and setting the value with
manifestPlaceholders = [ applicationName : appName ];
in the product flavour block so that the value gets set at compile time.
The problem comes when I try to append the build type to the application name. I can't seem to find a way to know what build type is currently being used within the product flavour.
This is a stripped down version of the build for readability
android {
buildVersionName "1.0.0
buildTypes {
release {
... nothing special
}
uat {
signingConfig signingConfigs.debug
buildType = "uat"
applicationIdSuffix = "." + buildType
}
debug {
signingConfig signingConfigs.debug
buildType = "uat"
applicationIdSuffix = "." + buildType
}
}
productFlavors{
flavor1{
def appName = "app name " + buildType;
manifestPlaceholders = [ applicationName : appName ];
applicationId [id]
def clientIteration = [client iteration]
versionName buildVersionName + clientIteration
versionCode [version code]
}
flavor2{
... same as above with different app name
}
flavor3{
... same as above with different app name
}
}
}
This code works fine except the variable 'buildType' is always the last buildtype (in this case debug) which means the app name always has debug on the end.
Probably worth noting that I don't need to have anything appended on the end of the app name for releases.
You can append the values like this
android {
productFlavors {
Foo {
applicationId "com.myexample.foo"
manifestPlaceholders = [ appName:"Foo"]
}
Bar {
applicationId "com.myexample.bar"
manifestPlaceholders = [ appName:"Bar"]
}
}
buildTypes {
release {
manifestPlaceholders = [ appNameSuffix:""]
}
debug {
manifestPlaceholders = [ appNameSuffix:".Debug"]
applicationIdSuffix ".debug"
}
}
}
and in the manifest
<application
android:label="${appName}${appNameSuffix}"
...
</application>
If you want to access different values based on build type you can do it like this
buildTypes {
debug{
buildConfigField "String", "Your_string_key", '"yourkeydebugvalue"'
buildConfigField "String", "SOCKET_URL", '"some text"'
buildConfigField "Boolean", "LOG", 'true'
}
release {
buildConfigField "String", "Your_string_key", '"yourkeyreleasevalue"'
buildConfigField "String", "SOCKET_URL", '"release text"'
buildConfigField "Boolean", "LOG", 'false'
}
}
And to access those values using build variants:
if(!BuildConfig.LOG)
// do something with the boolean value
Or
view.setText(BuildConfig.yourkeyvalue);
I know I'm a bit late for the party but if you want different names based on the flavours, you should have something like this:
productFlavors{
flavour 1 {
applicationId "your_app_id"
resValue "string", "app_name", "Flavour 1 app name"
.......
}
flavour 2 {
applicationId "your_app_id"
resValue "string", "app_name", "Flavour 2 app name"
.......
}
}
and in your AndroidManifest.xml:
android:label="#string/app_name"
Hope this helps.
This link http://inaka.net/blog/2014/12/22/create-separate-production-and-staging-builds-in-android/ may help you out.
If you have two productFlavors (Production and Staging, for instance)
You should create two different resource folders:
project/app/src/production/res/values/strings.xml
<resources>
<string name="root_url">http://production.service.com/api</string>
</resources>
project/app/src/staging/res/values/strings.xml
<resources>
<string name="root_url">http://staging.service.com/api</string>
</resources>
You should add this following code inside the android {}:
productFlavors {
production {
applicationId "com.inaka.app.production"
}
staging {
applicationId "com.inaka.app.staging"
}
}
It's a good idea to have different icons for different productFlavors, just add the icon inside each different resource folder.

Categories

Resources