I need to enable Fabric for different build environments and also take into account whether the apk has been built using Android Studio or a CI server (jenkins) in our case.
Approach that I am thinking of using is:
defaultConfig {
applicationId "com.pack.proj"
minSdkVersion 19
targetSdkVersion 23
versionCode 12
ext.buildNumber = System.getenv("BUILD_NUMBER") ?: "dev"
versionName "1.2.$buildNumber"
signingConfig signingConfigs.inspection
}
productFlavors {
dev1 {
resValue 'string', 'app_name', 'App Name'
resValue 'string', 'base_url', 'http://dev1.server.in/'
buildConfigField 'boolean', 'USE_FABRIC', 'true'
}
dev2 {
resValue 'string', 'app_name', 'App Name'
resValue 'string', 'base_url', 'http://dev2.server.in/'
// ********HOW DO I CALL THE TASK 'enableFabric' FROM HERE*********
}
}
task enableFabric{
if(versionName.contains('dev'))
buildConfigField 'boolean', 'USE_FABRIC', 'false'
else
buildConfigField 'boolean', 'USE_FABRIC', 'true'
}
Now my questions are
How do I call the task enableFabric from dev1 and dev2 product
flavors?
And when I run the gradle script I get the error that versionName is unrecognised property in task enableFabric?
also buildConfigField 'boolean', 'USE_FABRIC', 'true' when used in the defaultConfig does not work for me. when I use
if(BuildConfig.USE_FABRIC == true){
// DO something
}
in the Java code.
put the if else directly in dev2. or if you plan to use it more than once turn it into a function instead of task
example:
productFlavors {
dev1 {
resValue 'string', 'app_name', 'App Name'
resValue 'string', 'base_url', 'http://dev1.server.in/'
buildConfigField 'boolean', 'USE_FABRIC', 'true'
}
dev2 {
resValue 'string', 'app_name', 'App Name'
resValue 'string', 'base_url', 'http://dev2.server.in/'
buildConfigField 'boolean', 'USE_FABRIC', useFabric()
}
}
outside of your android block, do something like
def useFabric() {
if (versionName.contains('dev'))
return false;
else return true;
}
Related
I updated gradle 4.0.1 to 7.0.3 because I need the support of new gradle.
I let the auto updater run and after it was done, when I run the code I get the following error:
C:\Users\me\Projects\proj\proj\proj\app\build\generated\source\buildConfig\stage\debug\proj\BuildConfig.java:22: error: illegal forward reference
public static final String APPLICATION_LIST_URL = BACKEND_HOST + "/page";
In build.gradle the buildConfigField is declared like this:
defaultConfig {
applicationId "my.app.id"
minSdkVersion 21
versionCode getBuildTimestamp()
versionName "2.0.0"
buildConfigField 'String', 'APPLICATION_LIST_URL', 'BACKEND_HOST + "/page"'
}
I tried Invaldiate cache/restart and I do not know what else I can try.
EDIT
BACKEND_HOST is also defined:
productFlavors {
local {
dimension "type"
targetSdkVersion 30
buildConfigField 'String', 'APK_DOWNLOAD_RESOLVE_URL', 'BACKEND_HOST + "DOES_NOT_EXIST"'
...
}
remote {
dimension "type"
targetSdkVersion 30
applicationIdSuffix ".remote"
buildConfigField 'String', 'APK_DOWNLOAD_RESOLVE_URL', 'BACKEND_HOST + "/remote/download"'
}
def backendRemote= '"https://myUrl"'
android.applicationVariants.all {
variant ->
def appName = "myApp"
def backendHost = backendRemote
variant.resValue "string", "app_name", appName
resValue "string", "app_version", "${appName} ${variant.versionName}"
variant.buildConfigField "String", "AUTH_HOST", backendHost
variant.buildConfigField "String", "BACKEND_HOST", backendHost
}
}
And I was building it with remote flavor
It's unclear how the build tools determine the order of the field declarations in the BuildConfig. What works though is this (note the BuildConfig.BACKEND_HOST instead of just BACKEND_HOST):
buildConfigField 'String', 'BACKEND_HOST', 'my.backend.host.com'
buildConfigField 'String', 'APPLICATION_LIST_URL', 'BuildConfig.BACKEND_HOST + "/page"'
Chapter 8.3.3 of https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html explains what forward references are legal and which ones are illegal.
Here's a minimal code sample showing how the BACKEND_HOST can be defined in each flavor:
defaultConfig {
applicationId "com.example.myapplication"
minSdk 30
targetSdk 31
versionCode 1
versionName "1.0"
buildConfigField 'String', 'APPLICATION_LIST_URL', 'BuildConfig.BACKEND_HOST + "/page"'
}
flavorDimensions "version"
productFlavors {
free {
dimension "version"
buildConfigField "String", "BACKEND_HOST", '"www.free.com"'
}
paid {
dimension "version"
buildConfigField "String", "BACKEND_HOST", '"www.paid.com"'
}
}
This works because more specific BuildConfig fields (flavors) are evaluated first before the less specific ones (defaultConfig).
This code is copied from the OP's question and modified to compile by making the references to BACKEND_HOST static:
defaultConfig {
applicationId "my.app.id"
minSdkVersion 21
versionCode getBuildTimestamp()
versionName "2.0.0"
buildConfigField 'String', 'APPLICATION_LIST_URL', 'BuildConfig.BACKEND_HOST + "/page"'
buildConfigField "String", "BACKEND_HOST", '"www.paid.com"'
}
flavorDimensions "type"
productFlavors {
local {
dimension "type"
targetSdkVersion 30
buildConfigField 'String', 'APK_DOWNLOAD_RESOLVE_URL', 'BuildConfig.BACKEND_HOST + "DOES_NOT_EXIST"'
}
remote {
dimension "type"
targetSdkVersion 30
applicationIdSuffix ".remote"
buildConfigField 'String', 'APK_DOWNLOAD_RESOLVE_URL', 'BuildConfig.BACKEND_HOST + "/remote/download"'
}
}
def backendRemote= '"https://myUrl"'
android.applicationVariants.all {
variant ->
def backendHost = backendRemote
variant.buildConfigField "String", "AUTH_HOST", backendHost
variant.buildConfigField "String", "BACKEND_HOST", backendHost
}
I have a Android Library and I am using it in app module. In library I use a BuildConfig.SPECIAL_VALUE.
I would like to override this BuildConfig in my app module build gradle.
I found similary question but It doesn't help me (Access buildConfigField from gradle in Android app)
I try this but is not working:
My app module build.gradle:
android {
publishNonDefault true
compileSdkVersion 28
flavorDimensions "default"
buildToolsVersion '28.0.3'
defaultConfig {
applicationId "app....id"
flavorDimensions "default"
minSdkVersion 23
targetSdkVersion 28
versionCode 1
versionName "1.0.0"
multiDexEnabled true
renderscriptTargetApi 18
renderscriptSupportModeEnabled true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
buildConfigField 'boolean', 'DEBUG_LOG_ENABLED', 'false'
signingConfig signingConfigs.productivity_mentor_release_config
debuggable = false
manifestPlaceholders = [crashlyticsEnabled: true]
}
debug {
testCoverageEnabled = false
buildConfigField 'boolean', 'DEBUG_LOG_ENABLED', 'true'
debuggable = true
manifestPlaceholders = [crashlyticsEnabled: false]
}
unitTest {
testCoverageEnabled = false
buildConfigField 'boolean', 'DEBUG_LOG_ENABLED', 'false'
manifestPlaceholders = [crashlyticsEnabled: false]
}
}
productFlavors {
develop {
buildConfigField 'boolean', 'LOG_EVENTS_TO_REMOTE_ENABLED', 'false'
buildConfigField 'boolean', 'FIREBASE_CRASH_ENABLED', 'false'
buildConfigField 'String', 'SPECIAL_VALUE', '"11"'
}
production {
buildConfigField 'boolean', 'LOG_EVENTS_TO_REMOTE_ENABLED', 'true'
buildConfigField 'boolean', 'FIREBASE_CRASH_ENABLED', 'true'
buildConfigField 'String', 'SPECIAL_VALUE', '"22"'
}
beta {
buildConfigField 'boolean', 'LOG_EVENTS_TO_REMOTE_ENABLED', 'true'
buildConfigField 'boolean', 'FIREBASE_CRASH_ENABLED', 'true'
buildConfigField 'String', 'SPECIAL_VALUE', '"33"'
}
roboTest {
minSdkVersion 18
buildConfigField 'boolean', 'LOG_EVENTS_TO_REMOTE_ENABLED', 'false'
buildConfigField 'boolean', 'FIREBASE_CRASH_ENABLED', 'true'
buildConfigField 'String', 'SPECIAL_VALUE', '"44"'
}
}
testOptions {
unitTests.returnDefaultValues = true
}
lintOptions {
abortOnError false
}
compileOptions {
sourceCompatibility = 1.8
targetCompatibility = 1.8
}
And my library build.gradle:
android {
compileSdkVersion 28
flavorDimensions "default"
buildToolsVersion '28.0.3'
publishNonDefault true
defaultConfig {
minSdkVersion 22
targetSdkVersion 28
multiDexEnabled true
renderscriptTargetApi 18
renderscriptSupportModeEnabled true
javaCompileOptions {
annotationProcessorOptions {
arguments = ["room.schemaLocation":
"$projectDir/schemas".toString()]
}
}
}
buildTypes {
release {}
debug {}
unitTest { }
}
productFlavors {
develop {
buildConfigField 'boolean', 'LOG_EVENTS_TO_REMOTE_ENABLED', 'false'
buildConfigField 'boolean', 'FIREBASE_CRASH_ENABLED', 'false'
buildConfigField 'String', 'SPECIAL_VALUE', '"1"'
}
production {
buildConfigField 'boolean', 'LOG_EVENTS_TO_REMOTE_ENABLED', 'true'
buildConfigField 'boolean', 'FIREBASE_CRASH_ENABLED', 'true'
buildConfigField 'String', 'SPECIAL_VALUE', '"2"'
}
beta {
buildConfigField 'boolean', 'LOG_EVENTS_TO_REMOTE_ENABLED', 'true'
buildConfigField 'boolean', 'FIREBASE_CRASH_ENABLED', 'true'
buildConfigField 'String', 'SPECIAL_VALUE', '"3"'
}
roboTest {
minSdkVersion 18
buildConfigField 'boolean', 'LOG_EVENTS_TO_REMOTE_ENABLED', 'false'
buildConfigField 'boolean', 'FIREBASE_CRASH_ENABLED', 'true'
buildConfigField 'String', 'SPECIAL_VALUE', '"4"'
}
}
testOptions {
unitTests.returnDefaultValues = true
}
lintOptions {
abortOnError false
}
compileOptions {
sourceCompatibility = 1.8
targetCompatibility = 1.8
}
}
ext {
google_services_version = '16.0.7'
}
In my build.gradle (Module: app) I specified one buildConfigField and one resValue variable.
buildTypes {
release {
debuggable false
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
buildConfigField "String", "APP_EXP_DATE", "\"DEC 31 23:59:59 EDT 2018\""
resValue "String", "app_exp_date", "\"DEC 31 23:59:59 EDT 2018\""
}
}
Then I expected them to use in my Java code like this:
BuildConfig.APP_EXP_DATE
R.string.app_exp_date
but unfortunately I am experiencing the following errors:
error: cannot find symbol variable APP_EXP_DATE
error: illegal start of type
How can I make it work to be able to access variables from gradle in my Java code?
Well, you have some options:
Define your strings and values under defaultConfig as follow:
android {
// your code
defaultConfig {
// your code
resValue "string", "<key>", "<value>"
buildConfigField "string", "<key>", "<value>"
// ...
}
// your code
}
You can put your string in both Release and Debug type
buildTypes {
release {
// your code
resValue "string", "<key>", "<value>"
buildConfigField "string", "<key>", "<value>"
// ...
}
debug {
// your code
resValue "string", "<key>", "<value>"
buildConfigField "string", "<key>", "<value>"
// ...
}
}
Hope this help!
How can I make it work to be able to access variables from gradle in
my Java code?
The issue in your codes seems to be using in release buildType which might cause the issue (not resolving it.
But, this is how it should be :
In gradle.properties:
ExpDate="DEC 31 23:59:59 EDT 2018"
In app/Build.gradle (Note that it should be in android block code):
def APP_EXP_DATE = '"' + ExpDate + '"' ?: '"Define Expire Date"'
android.buildTypes.each { type ->
type.buildConfigField 'String', 'APP_EXP_DATE', ExpDate
}
Usage:
BuildConfig.APP_EXP_DATE
As a Toast:
Toast.makeText(activity, BuildConfig.APP_EXP_DATE, Toast.LENGTH_LONG).show()
I have six builds like
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.config
manifestPlaceholders = [appVersion: ""];
}
staging {
applicationIdSuffix '.staging'
versionNameSuffix '-staging'
manifestPlaceholders = [appVersion: "-stg"];
}
debug {
applicationIdSuffix '.debug'
versionNameSuffix '-debug'
manifestPlaceholders = [appVersion: "-debug"];
}
}
productFlavors {
panel {
versionCode 2
versionName '1.1'
applicationIdSuffix '.panel'
manifestPlaceholders = [appName: "exampleapp-panel"];
}
admin {
manifestPlaceholders = [appName: "exampleapp-admin"];
}
}
I want to change each function or variable for each build.
I can use it this way in XCode, but I have not found a way in Android studio.
Can I make a setting file using in AndroidStudio like this?
You can use something like following for each build/product flavor.
buildConfigField "boolean", "VALUE_KEY", "true"
resValue "string", "my_string", "Some string"
The first can be accessed in your code as BuildConfig.VALUE_KEY, the 2nd is written to strings.xml
try this :
productFlavors {
pro {
minSdkVersion 15
applicationId 'com.myapps'
signingConfig signingConfigs.release
targetSdkVersion 23
resValue "string", "app_name", "myapps"
buildConfigField "boolean", "IS_DEV", "false"
}
dev {
minSdkVersion 15
applicationId 'com.myapps.dev'
targetSdkVersion 23
resValue "string", "app_name", "myapps 1.2"
buildConfigField "boolean", "IS_DEV", "true"
}
}
I have two environment of my project one Prod another one is Staging. So whenever I have to build any of the environment, I have to change multiple keys like map key, label name and other things in manifest. So I have searched and find out some of the solutions and manifestPlaceholders is one of them.
Now what I want to do is to assign multiple value in manifestPlaceholders. So can I put multiple values in it and yes then how to put multiple values in it. Here is the code for the manifestPlaceholders
buildTypes {
debug {
manifestPlaceholders = [ google_map_key:"your_dev_key"]
}
release {
manifestPlaceholders = [ google_map_key:"prod_key"]
}
}
I have solved my problem as below code by adding multiple manifestPlaceholders values. Added this to my module build.gradle.
productFlavors {
staging {
applicationId "xxxxxxxxxxx"
manifestPlaceholders = [ google_map_key:"xxxxxxxxxx", app_label_name:"xxxxxxx"]
buildConfigField 'String', 'BASE_URL', '"xxxxxxxxxx"'
}
prod {
applicationId "xxxxxxxxxxx"
manifestPlaceholders = [ google_map_key:"xxxxxxxxxx", app_label_name:"xxxxxxx"]
buildConfigField 'String', 'BASE_URL', '"xxxxxxxxxx"'
}
}
EDIT:
You can use resValue also as Emanuel Moecklin suggested in comments.
productFlavors {
staging {
applicationId "xxxxxxxxxxx"
manifestPlaceholders = [ google_map_key:"xxxxxxxxxx", app_label_name:"xxxxxxx"]
buildConfigField 'String', 'BASE_URL', '"xxxxxxxxxx"'
resValue "string", "base_url", "xxxxxxxxxx"
}
prod {
applicationId "xxxxxxxxxxx"
manifestPlaceholders = [ google_map_key:"xxxxxxxxxx", app_label_name:"xxxxxxx"]
buildConfigField 'String', 'BASE_URL', '"xxxxxxxxxx"'
resValue "string", "base_url", "xxxxxxxxxx"
}
}
You can easily set/change multiple manifestPlaceholders values. You can either define all values at once, as in your answer, or one by one.
defaultConfig {
// initialize more values
manifestPlaceholders = [ google_map_key:"xxxxxxxxxx", app_label_name:"xxxxxxx"]
// or this way
manifestPlaceholders.google_map_key = "xxxxxxxxxx"
manifestPlaceholders.app_label_name = "xxxxxxxxxx"
}
productFlavors {
staging {
}
prod {
// use some different value for prod
manifestPlaceholders.google_map_key = "yyyyyyyyyy"
}
}
I have mentioned for both build Types and flavors
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
resValue "string", "google_maps_key", "release google map key"
}
debug {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
resValue "string", "google_maps_key", "debug google map key"
}
}
productFlavors {
alpha {
applicationId = "com.example.alpha"
resValue 'string', 'app_name', 'alphaapp'
resValue "string", "maps_api_key", "XXXXXXXXXXXXXXXXXXXXX"
}
beta {
applicationId = "com.example.beta"
resValue 'string', 'app_name', 'betaapp'
resValue "string", "maps_api_key", "XXXXXXXXXXXXXXXXXXXXXX"
}
}
I could not use the suggested approaches in other answers because gradle seems to have changed the type of manifestPlaceholders to val mutablemap in a recent release.
This was the only fix that worked for me:
manifestPlaceholders["key"] = "value0"
manifestPlaceholders["key"] = "value1"
Well, we can set manifestPlaceholders key values using the following ways,
select File > Project Strucutre
Add environment
2-1. select Flavors tab
2-2. Add flavor dimension and name for dimension ex."env"
2-3. Add product flavor an name product ex. "prod"
Add manifestPlaceHolder keys
3-1. Select the above product
3-2. Add key in Manifest Placeholders list
press OK
build.gradle file is automatic updated after press the buttton