Is there an easy way include common feature settings in gradle - android

Is there an easy way to include common flavor settings in a flavor when the flavors are split out by build settings?
Take the below example. I'd like to have all the settings in the flavor1 group below included in both the Debug and Release flavors. This is obviously a simplified example, as I have 4 flavors and over 20 settings common between them and I don't wan to duplicate them.
android {
productFlavors {
flavor1Debug {
resValue 'string', 'application_name', 'DebugName'
}
flavor1Release {
resValue 'string', 'application_name', 'RelaseName'
}
//flavor1 {
// buildConfigField 'String', 'DEFAULT_LANGUAGE_CODE', '"en"'
//}
}
}

There is a defaultConfig section, you can provide the base configuration for all flavors in the defaultConfig block, and each flavor can change any of these default values.
for example:
android {
defaultConfig {
manifestPlaceholders = [hostName:"www.example.com"]
...
}
buildTypes {
debug{...}
release{...}
}
flavorDimensions "version"
productFlavors {
demo {
dimension "version"
manifestPlaceholders = [hostName:"www.otherexample.com"]//this flavor change manifestPlaceholders
...
}
full {
dimension "version" //this flavor extends manifestPlaceholders from `defaultConfig`
...
}
}

Related

Right way to add different configurations for different build types and product flavours

In my application I have 4 environments i.e Dev, SIT, UAT, Release. For each environment I have a build type with it's own configuration. Much like the suggested way, e.g:
buildTypes {
Dev {
buildConfigField "String", 'BASE_URL', "https://dev-api.yourbackend.com"
}
SIT {
buildConfigField "String", 'BASE_URL', "https://sit-api.yourbackend.com"
}
UAT {
buildConfigField "String", 'BASE_URL', "https://uat-api.yourbackend.com"
}
Release {
buildConfigField "String", 'BASE_URL', "https://api.yourbackend.com"
}
}
But now I have 5-6 different such configurations, not just the BASE_URL. Like ClientId, ClientSecret etc..
Plus I have 2 product flavours, meaning I need to create 8 different build variants and have all these 5-6 configurations inside each such variant. All that looks clumsy.
1 other solution I found is to create a folder for each of the build variant like flavour1Dev, flavour2Sit, flavour2Uat etc.. and have the config file specific to that variant inside that folder. This again involves 8 different folders and keeps growing as we add more environments.
Is there a better way of handling this, probably like a config.gradle file where I can only have these configurations and import it back in the app/build.gradle, a way of modularising the whole build variant configurations.
Update-1
I tried this as per #Md. Asaduzzaman's Answer:
build.gradle
…
…
apply from: './config.gradle'
…
…
android {
…
…
defaultConfig {
…
…
buildConfigField('String', ‘BASE_URL’, '"https://default.yourbackend.com”')
}
…
…
}
config.gradle
android {
buildTypes {
dev {
buildConfigField('String', ‘BASE_URL’, '"https://dev.yourbackend.com”')
}
sit {
buildConfigField('String', ‘BASE_URL’, '"https://sit.yourbackend.com”')
}
}
}
The issue is that in the generated BuildConfig, I still see the default values:
public static final String BASE_URL = "https://default.yourbackend.com";
You already mentioned the solution yourself by creating separate config.gradle file. I try to implement it like below:
Step - 1: Create config.gradle inside your app folder and add all the configurations.
android {
buildTypes {
Dev {
buildConfigField "String", 'BASE_URL', "https://dev-api.yourbackend.com"
}
SIT {
buildConfigField "String", 'BASE_URL', "https://sit-api.yourbackend.com"
}
UAT {
buildConfigField "String", 'BASE_URL', "https://uat-api.yourbackend.com"
}
Release {
buildConfigField "String", 'BASE_URL', "https://api.yourbackend.com"
}
}
productFlavors {
flavor1 {
/*implementation*/
}
flavor2 {
/*implementation*/
}
flavor3 {
/*implementation*/
}
}
}
Step -2: Include the config.gradle in your app/build.gradle.
apply plugin: 'com.android.application'
apply from: './config.gradle'
....

Gradle variable from another applicationId flavor

I need to build an application created with a flavor and create a dynamic variable who points to an applicationId of another flavor (Because the code of an internal library uses the applicationId of other applications) but I don't know how to do that.
Here is the sample code :
defaultConfig {
applicationId "com.sample.mycompany"
}
buildTypes {
release {
}
qualif {
applicationIdSuffix = ".qual"
}
debug {
applicationIdSuffix = ".dev"
}
}
flavorDimensions "client", "nature"
productFlavors {
ClientA {
dimension "client"
applicationIdSuffix = ".A"
}
ClientB {
dimension "client"
applicationIdSuffix = ".B"
}
NatureX {
dimension "nature"
applicationIdSuffix = ".X"
}
NatureY {
dimension "nature"
applicationIdSuffix = ".Y"
// A buildconfigField variable here to get com.sample.mycompany[client].X[buildTypes]
}
NatureZ {
dimension "nature"
applicationIdSuffix = ".Z"
// A buildConfigField variable here to get com.sample.mycompany[client].X[buildTypes]
}
}
When I compile with the Build Variant : ClientANatureYDebug
, final applicationId is com.sample.mycompany.A.Y.dev
I want a dynamic variable with buildConfigField (or something else to retrieve the new variable in Java) who is com.sample.mycompany.A.X.dev
I think to get the final applicationId and replace the applicationIdSuffix of the current nature compilation dimension by .X and get the result in a new variable but I do not know how. Can you help me ?
Fixed with :
buildConfigField "String", "VAL_SHARE_TO_RECEIVER_APP_ID", "APPLICATION_ID.replace(\".Y\", \".X\")"

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

Properties for each product flavor in Gradle

Is it possible to create two .properties files for two product flavors in Gradle?
I'm building an Android app with two flavors and I want to have separate properties for them, but have problems with overwritten variable here:
productFlavors {
flavor1 {
customProperties = getCustomProperties("flavor1.properties");
}
flavor2 {
customProperties = getCustomProperties("flavor2.properties");
}
}
My customProperties variable is always get values from flavor2 properties, even I build flavor1.
What am I doing wrong? :)
upd: defaultConfig:
defaultConfig {
minSdkVersion 17
targetSdkVersion 22
// Enabling multidex support.
multiDexEnabled true
}
I have use something like this:
flavorDimensions "default"
productFlavors {
stand {
def standPropsFile = file("${project.projectDir}/../stand.properties")
Properties standProps = new Properties()
if (standPropsFile.canRead()) {
standProps.load(new FileInputStream(standPropsFile))
}
manifestPlaceholders = standProps
applicationId = manifestPlaceholders["APP_ID"]
}
google {
def standPropsFile = file("${project.projectDir}/../google.properties")
Properties standProps = new Properties()
if (standPropsFile.canRead()) {
standProps.load(new FileInputStream(standPropsFile))
}
manifestPlaceholders = standProps
applicationId = manifestPlaceholders["APP_ID"]
}
}
manifestPlaceholders - is just setter for Map<String, Object> mManifestPlaceholders, so after "manifestPlaceholders = standProps" you can use values right by key how you have write it in .properties file.
You should also change the build variant and select the right flavor to bring every configuration for the desired flavor into effect.
Alternatively, if you have only a few fields in the properties file and just want different values for each flavor: you could use BuildConfigFields as follows:
buildConfigField 'String', 'FIELD1', '"value1"'
buildConfigField 'String', 'FIELD2', '"value2"'
buildConfigField "String", "FIELD3", "value2"
These can be accessed anywhere throughout the project using the BuildConfig class as follows:
BuildConfig.FIELD1
BuildConfig.FIELD2
BuildConfig.FIELD3

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