buildConfigField not working after updating gradle to 7.0.3 - android

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
}

Related

How can I create a unique variable for each build in Android Studio?

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"
}
}

define manifest place holders in build.gradle

I have a few manifest placeholders in my AndroidManifest.xml file
In build.gradle I want to dynamically populate those values depending on my flavor and build type.
How can I do that ?
I wrote a function that does the following
def getKey() {
def KeyToReturn = ""
android.applicationVariants.all { variant ->
printout("getKey: ${variant.name}")
def flavor = "default";
if (variant.productFlavors.size() > 0)
flavor = variant.productFlavors.get(0);
def buildType = variant.buildType.name
if (buildType == "debug" || buildType == "staging") {
if (flavor.name == "one") {
KeyToReturn = test_key_1
}
if (flavor.name == "two") {
KeyToReturn = test_key_2
}
}
if (buildType == "release") {
if (flavor.name == "one") {
KeyToReturn = live_key_1
}
if (flavor.name == "two") {
KeyToReturn = live_key_2
}
}
}
printout("KeyToReturn:" + KeyToReturn)
return KeyToReturn
}
I have this in my android.defaultConfig
defaultConfig {
minSdkVersion 15
targetSdkVersion 23
versionCode getVersionCode1()
versionName getVersionName1() + ""
manifestPlaceholders = [key: getKey()]
}
This is what my AndroidManifest.xml relevant part contains
<meta-data
android:name="key"
android:value="${key}"/>
The problem is when I look in the built AndroidManifest.xml file
the ${key} value is an empty string.
How do I populate this value correctly ?
You define manifest placeholders based on product flavors (and AFAIK build type) by adding them to the proper closure.
In this sample app, I use product flavors to use different rules for Android 7.0's network security configuration:
productFlavors {
thawte {
resValue "string", "app_name", "CA Validation Demo"
applicationId "com.commonsware.android.downloader.ca.thawte"
manifestPlaceholders=
[networkSecurityConfig: 'network_thawte']
buildConfigField "String", "URL", WARES
}
verisign {
resValue "string", "app_name", "Invalid CA Validation Demo"
applicationId "com.commonsware.android.downloader.ca.verisign"
manifestPlaceholders=
[networkSecurityConfig: 'network_verisign']
buildConfigField "String", "URL", WARES
}
system {
resValue "string", "app_name", "System CA Validation Demo"
applicationId "com.commonsware.android.downloader.ca.system"
manifestPlaceholders=
[networkSecurityConfig: 'network_verisign_system']
buildConfigField "String", "URL", WARES
}
pin {
resValue "string", "app_name", "Cert Pin Demo"
applicationId "com.commonsware.android.downloader.ca.pin"
manifestPlaceholders=
[networkSecurityConfig: 'network_pin']
buildConfigField "String", "URL", WARES
}
invalidPin {
resValue "string", "app_name", "Cert Pin Demo"
applicationId "com.commonsware.android.downloader.ca.invalidpin"
manifestPlaceholders=
[networkSecurityConfig: 'network_invalid_pin']
buildConfigField "String", "URL", WARES
}
selfSigned {
resValue "string", "app_name", "Self-Signed Demo"
applicationId "com.commonsware.android.downloader.ca.ss"
manifestPlaceholders=
[networkSecurityConfig: 'network_selfsigned']
buildConfigField "String", "URL", SELFSIGNED
}
override {
resValue "string", "app_name", "Debug Override Demo"
applicationId "com.commonsware.android.downloader.ca.debug"
manifestPlaceholders=
[networkSecurityConfig: 'network_override']
buildConfigField "String", "URL", SELFSIGNED
}
}
I can then reference the placeholder in the manifest normally:
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:networkSecurityConfig="#xml/${networkSecurityConfig}">

How to call a gradle task from productflavor

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;
}

Android different packageName with flavors

I need to install 2 versions of my project (Production and Development). I need 2 apps. I'm trying to achive it by using flavors, but when I sign the apk, it always generate the same app, with the same packageName (com.company.project). I've tried removing the applicationId from the defaultConfig but it doesn't work neither.In the manifest, the package name is com.company.project.
Anyone knows how to do that?
This is the build.gradle
defaultConfig {
multiDexEnabled true
minSdkVersion 16
targetSdkVersion 23
versionCode 1
versionName "1.0"
applicationId "com.company.project"
}
productFlavors {
development {
applicationId
"com.company.project.DEV"
versionName "1.0-dev"
resValue "string", "app_name", "Project-Dev"
}
production {
applicationId
"com.company.project.PROD"
resValue "string", "app_name", "Project-Prod"
versionName "1.0-prod"
}
}
When you create productFlavors then the corresponding gradle tasks also changes.
For instance, originally you have only assembleDebug and assembleRelease. But, after implementing productFlavors, the gradle tasks will change. Taking your example in consideration, it will be
assembleDevelopmentDebug
assembleDevelopmentRelease
assembleProductionDebug
assembleProductionRelease
If you are using Android Studio, then you do not have to worry about the gradle tasks. Just select the Build Variant from the menu and build the project. It will run the corresponding gradle tasks and install the build.
I have written a blog explaining this, Product Flavors in Android. A sample project is also available on GitHub.
I'm doing a similar thing and my build.gradle looks like this and it works:
flavorDimensions 'Level'
productFlavors {
alpha {
dimension 'Level'
applicationIdSuffix '.alpha'
}
beta {
dimension 'Level'
applicationIdSuffix '.beta'
}
major {
dimension 'Level'
}
}
I actually set this up in Build -> Edit Flavors and it generated everything for me.
Finally I did it like this:
def appName = 'AppName'
productFlavors {
devel {
applicationIdSuffix ".devel"
def buildId, appNameLabel
buildId = androidApplicationId + '.devel' + androidVersionCode
appNameLabel = appName + 'd' + androidVersionName
buildConfigField "String", "BUILD_ID", '"' + buildId + '"'
manifestPlaceholders = [app_name_label: appNameLabel, buildId: buildId] }
QA {
applicationIdSuffix ".qa"
def buildId, appNameLabel
buildId = androidApplicationId + '.qa' + androidVersionCode
appNameLabel = appName + 'q' + androidVersionName
buildConfigField "String", "BUILD_ID", '"' + buildId + '"'
manifestPlaceholders = [app_name_label: appNameLabel, buildId: buildId]
}
pro {
buildConfigField "String", "BUILD_ID", '"' + androidApplicationId + '"'
manifestPlaceholders = [app_name_label: appName, buildId: androidApplicationId]
}

Is there a way to change gradle variable value based on selected productFlavor?

Below is my gradle example:
I want to change STORE_FILE_PATH value dynamically based on selected productFlavors. Currently STORE_FILE_PATH is always overwriting it's value with last defined productFlavor. (In my case it always becomes "/pro.jks")
Help me find solution. Thanks
def STORE_FILE_PATH = "";
android {
productFlavors {
free {
versionCode 1
versionName "1.0.0"
applicationId "com.example.free"
buildConfigField "boolean", "IS_AD_ENABLED", "true"
STORE_FILE_PATH = "/free.jks"
}
pro {
versionCode 1
versionName "1.0.0 pro"
applicationId "com.example.pro"
buildConfigField "boolean", "IS_AD_ENABLED", "false"
STORE_FILE_PATH = "/pro.jks"
}
}
signingConfigs {
signingConfig {
keyAlias 'aa'
keyPassword '123'
storeFile file (STORE_FILE_PATH)
storePassword '123'
}
}
}
You should define multiple signingConfigs and use it in different productFlavors
signingConfigs{
freeKey{}
proKey{}
}
productFlavors {
free {
versionCode 1
versionName "1.0.0"
applicationId "com.example.free"
buildConfigField "boolean", "IS_AD_ENABLED", "true"
signingConfig signingConfigs.freeKey
}
pro {
versionCode 1
versionName "1.0.0 pro"
applicationId "com.example.pro"
buildConfigField "boolean", "IS_AD_ENABLED", "false"
signingConfig signingConfigs.proKey
}
}

Categories

Resources