Android different packageName with flavors - android

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

Related

buildConfigField not working after updating gradle to 7.0.3

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
}

Is it possible to get the versionName without the suffix from Android?

Consider app.gradleincludes the following:
defaultConfig {
versionName "2.1.6"
}
debug {
debuggable true
versionNameSuffix "-debug"
}
Is it possible to get the version name without the suffix? When using PackageInfo pInfo = applicationContext.getPackageManager().getPackageInfo(applicationContext.getPackageName(), 0);
pInfo.versionName returns 2.1.6-debug is there a way to get only 2.1.6 without doing some string or regex matching.
Thank you!
I would do it using generated BuildConfig:
Gradle
defaultConfig {
def version = "2.1.6"
versionName version
buildConfigField "String", "VERSION", "\"$version\""
}
Java
String version = BuildConfig.VERSION;
Question is old, but it might help someone - I have looked for something similar recently and used this:
debug{
buildConfigField "String", "APP_VER", "\"" + android.defaultConfig.versionName + "\""
}
OR for all buidTypes
buildTypes.each {
it.buildConfigField "String", "APP_VER", "\"" + android.defaultConfig.versionName + "\""
}
OR for all app variants:
applicationVariants.all { variant ->
variant.buildConfigField "String", "APP_VER", "\"" + android.defaultConfig.versionName + "\""
}

Android app name depends on buildType and flavours Gradle

Below is an extract from my gradle source code. What I want to achieve is to add suffix to app name when buildType.debug is executed. I tried the following code, but variables are in gradle assigned in sequence as they are written in file and not as task order. So in the example below buildVariant variable will always be equal to Release.
{
def buildVariant = ""
buildTypes {
debug {
manifestPlaceholders = [showDebug: 'true']
buildVariant = " (DEBUG)"
}
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
manifestPlaceholders = [showDebug: 'false']
signingConfig signingConfigs.myConf
buildVariant = " Release"
}
}
productFlavors {
flavour1{
resValue 'string', 'app_name', 'Flavour1'+buildVariant
}
flavour2{
resValue 'string', 'app_name', 'Flavour2'+buildVariant
}
flavour3{
resValue 'string', 'app_name', 'Flavour3'+buildVariant
}
}
It was a really interesting puzzle to solve, so thanks for the question!
Here what you can do:
android {
compileSdkVersion 23
buildToolsVersion "23.0.0"
defaultConfig {
....
}
buildTypes {
debug {
}
release {
}
}
productFlavors {
FlavorA {
}
FlavorB {
}
}
applicationVariants.all { variant ->
variant.resValue "string", "app_name", '"' + variant.productFlavors.get(0).name + '_' + variant.buildType.name + '"'
}
}
dependencies {
}
As a result, it'd print the app name "FlavorA_debug", "FlavorB_release", etc.
(NB! I ran it with gradle classpath 'com.android.tools.build:gradle:1.3.0' - works great, though I didn't try with older versions)

How do I configure a variant to run both prod & debug app on same Android?

I added the following to my build.gradle:
def applicationId() { "com.rithmio.coach" }
def applicationName() { "Coach Rithmio" }
defaultConfig {
applicationId applicationId()
minSdkVersion 19
targetSdkVersion 22
versionCode gitVersion()
versionName "${versionMajor()}.${versionMinor()}.${versionPatch()}"
}
buildTypes {
debug {
applicationIdSuffix ".debug"
resValue "string", "app_name", "Coach (Debug)"
final CONTENT_AUTHORITY = "${applicationId()}${applicationIdSuffix}.content"
resValue "string", "content_authority", CONTENT_AUTHORITY
final ACCOUNT_TYPE = "${applicationId()}${applicationIdSuffix}.account"
resValue "string", "account_type", ACCOUNT_TYPE
}
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
resValue "string", "app_name", "${applicationName()}"
final CONTENT_AUTHORITY = "${applicationId()}.content"
resValue "string", "content_authority", CONTENT_AUTHORITY
// If you're plugging into the account auth system
final ACCOUNT_TYPE = "${applicationId()}.account"
resValue "string", "account_type", ACCOUNT_TYPE
}
}
But this breaks my application in debug mode, all of the sudden the root classes are not where they are supposed to be.
It's looking for a class com.rithmio.coach.debug.mobile.* but it should be looking for com.rithmio.coach.mobile.*
How would i save modify this to look in the correct package?
Caused by: java.lang.ClassNotFoundException:
find class "com.rithmio.coach.debug.mobile.ScrollAwareFabBehavior"
on path: DexPathList[[zip file "/data/app/com.rithmio.coach.debug-1/base.apk"],
nativeLibraryDirectories=[/data/app/com.rithmio.coach.debug-1/lib/arm,
/vendor/lib, /system/lib]]
I basically want to change the applicationid without changing the package name.
How define product flavors in the build file :-
To define two product flavors, edit the build file for the app module to add the following configuration:-
...
android {
...
defaultConfig { ... }
signingConfigs { ... }
buildTypes { ... }
productFlavors {
demo {
applicationId "com.buildsystemexample.app.demo"
versionName "1.0-demo"
}
full {
applicationId "com.buildsystemexample.app.full"
versionName "1.0-full"
}
}
}
...
The product flavor definitions support the same properties as the defaultConfig element. The base configuration for all flavors is specified in defaultConfig, and each flavor overrides any default values. The build file above uses the applicationId property to assign a different package name to each flavor: since each flavor definition creates a different app, they each need a distinct package name.
More detailed answer here :-
https://developer.android.com/tools/building/configuring-gradle.html

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