I have two flavors in my Android project, one works with test server and one with production. I store the URL inside a string resource, so I may access the correct URL based on a flavor that I choose for compilation. Usually I need to create multiple apk files during a day, each time for both servers.
Is there a way to create two apk files each time I run my project or build an apk from Build menu?
If you have something like this:
android {
productFlavors {
dev {
applicationId "your.com.android.devel"
buildConfigField 'String', 'HOST', '"http://192.168.1.78"'
}
prod {
applicationId "your.com.android"
buildConfigField 'String', 'HOST', '"http://yourserver.com"'
}
}
}
You only have to run assemble in Gradle projects
And you can find all the different apks build/outputs/apk
Hope this time I'd be more helpful
Mastering "Product Flavors" on Android
The only thing you have to do is to define it on each of your product flavors:
android {
productFlavors {
devel {
applicationId "zuul.com.android.devel"
}
prod {
applicationId "zuul.com.android"
}
}
}
Send requests to multiple hosts depending on the flavor
As before, you must include some params on your product flavor config field.
android {
productFlavors {
devel {
applicationId "zuul.com.android.devel"
buildConfigField 'String', 'HOST', '"http://192.168.1.34:3000"'
}
prod {
applicationId "zuul.com.android"
buildConfigField 'String', 'HOST', '"http://api.zuul.com"'
}
}
}
As an example, we will try to show you how you can integrate this with Retrofit to send request to the appropiate server without handling which server you're pointing and based on the flavor. In this case this is an excerpt of the Zuul android app:
public class RetrofitModule {
public ZuulService getRestAdapter() {
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(BuildConfig.HOST)
.setLogLevel(RestAdapter.LogLevel.FULL)
.build();
return restAdapter.create(ZuulService.class);
}
}
As you can see you just have to use the BuildConfigclass to access the variable you've just defined.
You can use this command line in Gradle:
./gradlew assemble
Or you can generate saparately all flavors for debug or release respectively
./gradlew assembleDebug
./gradlew assembleRelase
Related
I have 3 mode of build types- debug, stage, release.
FCM, Firebase analytics had been integrated on my app.
My goal is to link different Firebase projects in each mode of my build.
As an example, if I build my app in stage mode, then Firebase project project_stage should be linked to my app, so all firebase settings should be worked with project_stage.
If I do some action, then analytics will be logged to project_stage, and I would need to get notification from project_stage.
Same for project_live and project_debug.
I have tried several ways but didn't work for me.
Pass the desired name as buildConfigField FIREBASE_APP_NAME or R.string.firebase_app_name:
android {
// default configuration, don't touch.
defaultConfig {
buildConfigField "String", "FIREBASE_APP_NAME", "\"default\""
resValue("string", "firebase_app_name", "default")
}
buildTypes {
debug {}
staging {}
release {}
}
sourceSets {
main {} // default source-set
foo {}
bar {}
}
productFlavors {
foo {
buildConfigField "String", "FIREBASE_APP_NAME", "\"foo\""
resValue("string", "firebase_app_name", "foo")
}
bar {
buildConfigField "String", "FIREBASE_APP_NAME", "\"bar\""
resValue("string", "firebase_app_name", "bar")
}
}
}
One can likely either configure productFlavors or buildTypes, unless combining app names. However, then one can instance FirebaseApp with the name inside the application package:
FirebaseApp.getInstance(BuildConfig.FIREBASE_APP_NAME);
Or with string resource:
FirebaseApp.getInstance(getString(R.string.firebase_app_name));
There's also an android.environments Gradle plugin for generating these buildConfigField.
Likewise, one could just use a string resource in the proper res directory. When configuring productFlavors and sourceSets with the same names (and obviously also the corresponding directories & files), one can configure all the rest with string resources, instead of Android DSL.
Gradle sourceSets permit for more than just alternate string resources ...
I need to create a mobile app artifact for multiple env. The goal is to promote the same artifact across multiple envs (dev, qa, preprod and prod). The mobile artifact uses a saas url which changes from env to env. Please let me know the best practice to do so.
Currently when the artifact passes qa I create another artifact for pre-prod and finally for prod which is time-consuming and prone to mistakes.
I am thinking of creating an active env url and release version api. What is the best practice?
Thanks,
I think android-flavors will solve your problem.
I look like these examples below.
flavorDimensions "default"
productFlavors{
dev{
applicationId "com.amitgupta.trust_app_android.dev"
}
staging{
applicationId "com.amitgupta.trust_app_android.staging"
}
qa{
applicationId "com.amitgupta.trust_app_android.qa"
}
production{
applicationId "com.amitgupta.trust_app_android.production"
}
}
You make also use different URLs based on Different environment.
flavorDimensions "version"
productFlavors {
QA {
buildConfigField "String", "BASE_URL", '"http://qa.com/api/"'
}
production {
buildConfigField "String", "BASE_URL", '"http://production.com/api/"'
}
}
Please, look at these for its implementation.
https://medium.com/#hsmnzaydn/configuration-product-flavors-and-build-variants-in-android-bb9e54d459af
https://www.journaldev.com/21533/android-build-types-product-flavors
For iOS:
You can make use of Schemes and Build configurations in Xcode. Here's the official documentation: https://developer.apple.com/library/ios/recipes/xcode_help-project_editor/Articles/BasingBuildConfigurationsonConfigurationFiles.html
I hope this will be of any help.
The following is true if you use gradle:
For top level build.gradle, define appId parameter:
allprojects {
ext {
appId = 'com.my.app'
}
}
For app module's build.gradle, define flavors and use the above parameter:
android {
def globalConfig = rootProject.extensions.getByName("ext")
productFlavors {
dev {
applicationId globalConfiguration["appId"] + ".dev"
...
buildConfigField "String", "YOUR_ENDPOINT", "\"https://my.dev.env/\""
}
qa {
applicationId globalConfiguration["appId"] + ".qa"
...
buildConfigField "String", "YOUR_ENDPOINT", "\"https://my.qa.env/\""
}
}
Build app using specific flavor + use BuildConfig.YOUR_ENDPOINT in code.
I have 2 build types of my application: debug and release.
I want to execute tests on both build types.
But currently only one Build Type is tested. By default it is the debug Build Type, but this can be reconfigured with:
android {
...
testBuildType "release"
}
I want to execute connectedDebugAndroidTest and connectedReleaseAndroidTest both one by one without changing gradle file.
Is it possible to make "testBuildType" conditional ?
So that according to build variant in gradle task (connectedDebugAndroidTest and connectedReleaseAndroidTest), it will execute tests on that build.
I am not sure but this is worked for me. If you want to execute code according to building variable (debug and released) in app then you can do by using following code.
This is for Activity java file.
public void printMessage()
{
if (BuildConfig.DEBUG)
{
//App is in debug mode
}
else
{
//App is released
}
}
If you want to check in build.gradle file then do by following code.
First way
buildTypes {
debug {
buildConfigField "String", "SERVER_URL", '"http://test.this-is-so-fake.com"'
}
release {
buildConfigField "String", "SERVER_URL", '"http://prod.this-is-so-fake.com"'
}
mezzanine.initWith(buildTypes.release)
mezzanine {
buildConfigField "String", "SERVER_URL", '"http://stage.this-is-so-fake.com"'
}
}
Second way
android {
testBuildType obtainTestBuildType()
}
def obtainTestBuildType() {
def result = "debug";
if (project.hasProperty("testBuildType")) {
result = project.getProperties().get("testBuildType")
}
result
}
For detail please check this, this and this stackoverflow answer.
I hope you will get your solution.
How is it possible to identify the current flavor being compiled. I'm trying to add a file to compile only if I'm compiling a certain product flavor.
buildTypes {
android.applicationVariants.all { variant ->
variant.productFlavors.each() { flavor ->
if (flavor.name.equals(currentFlavorName)) {
The problem is that I can't seem to find where the currentFlavourName of the flavor which I am currently building is located.
just put the strings you want for flavor1 into:
src/flavor1/res/values/strings.xml
and the strings for flavor2 into:
src/flavor2/res/values/strings.xml
no need to put logic into your gradle file
Android uses a unique build process regarding your resources for different flavors and it is very easy to control.
if you set up your main source:
project-name
------------/app
---------------/src
-------------------/main
------------------------/res
----------------------------/values
------------------------/java
-------------------/development
-------------------------------/res
-----------------------------------/values
-------------------------------/java
-------------------/production
------------------------------/res
----------------------------------/values
------------------------------/java
This would be a bottom up approach from product flavor into main. Meaning if you have a strings.xml with items having the same name existing in development/res/values and have values that also exist in main/res/values/strings.xml these will be over written (and same would go for the production flavor) based on the build variant defined in your gradle file.
android {
productFlavors {
production {
applicationId "com.test.prod"
versionName "1.0.0"
}
development {
applicationId "com.test.dev"
versionName "1.0.0"
}
}
I don't know if exits a method to get the currentFlavor. I haven't found it yet.
A ugly solution can be
variant.productFlavors.each() { flavor ->
if (flavor.name.equals("flavor1")) {
//..........
}
}
However, if you want to be able to control which strings.xml you are using, you can achieve it in different ways.
First of all you can just define a xml file in your flavor folder.
app/src/main/res/values/ -> for common resources
app/src/flavor1/res/values -> resources for flavor1
app/src/flavor2/res/values -> resources for flavor2
This doesn't require any config in your build.gradle script.
A second option is to define a resource value using build.gradle.
Something like:
productFlavors {
flavor1 {
resValue "string", "app_name", "IRCEnterprise"
}
//....
}
Another option is to create some field in your BuildConfig class using this kind of script.
productFlavors {
flavor1 {
buildConfigField "String", "name", "\"MY FLAVOR NAME\""
}
}
Is it possible to change the package name of an Android application using Gradle?
I need to compile two copies of the same app, having a unique package name (so I can publish to the market twice).
As a simpler alternative to using product flavours as in Ethan's answer, you can also customise build types.
How to choose between the approaches:
If you need different package names to be able to have both debug and release apks installed on a device, then use the build type approach below, as Gradle plugin docs agree. In this case flavours are an overkill. (I think all projects should by default do this, as it will make life easier especially after you've published to the store and are developing new features.)
There are valid uses for product flavours, the typical example being an app with free and paid versions. In such case, check Ethan's answer and read the documentation too: Configuring Gradle Builds and Gradle Plugin User Guide.
(You can also combine the two approaches, which results in every build variant having distinct package name.)
Build type configuration
For debug build type, and all other non-release types, define applicationIdSuffix which will be added to the default package name.
(Prior to Android Gradle plugin version 0.11 this setting was known as packageNameSuffix.)
android {
buildTypes {
debug {
applicationIdSuffix '.debug'
versionNameSuffix '-DEBUG'
}
beta {
applicationIdSuffix '.beta'
versionNameSuffix '-BETA'
// NB: If you want to use the default debug key for a (non-debug)
// build type, you need to specify it:
signingConfig signingConfigs.debug
}
release {
// signingConfig signingConfigs.release
// runProguard true
// ...
}
}
}
Above, debug and release are default build types whose some aspects are configured, while beta is a completely custom build type. To build the different types, use assembleDebug, assembleBeta, etc, as usual.
Similarly, you can use versionNameSuffix to override the default version name from AndroidManifest (which I find very useful!). E.g. "0.8" → "0.8-BETA", as configured above.
Resources:
This example is straight from Xavier Ducrohet's "Google I/O 2013: The New Android SDK Build System" presentation.
Build Types in the User Guide.
Myself I've been using productFlavors so far for this exact purpose, but it seems build type customisation may be closer to my needs, plus it keeps the build config simpler.
Update (2016): I've since used this approach in all my projects, and I think it definitely is the way to go. I also got it included in Android Best Practices guide by Futurice.
You could so something like this
android {
...
defaultConfig {
minSdkVersion 8
versionCode 10
}
flavorDimensions "flavor1", "flavor2"
productFlavors {
flavor1 {
applicationId "com.example.flavor1"
versionCode 20
}
flavor2 {
applicationId "com.example.flavor2"
minSdkVersion 14
}
}
}
You can also change the field android.defaultConfig.applicationId if you want to do one-off builds.
Taken from: http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Product-Flavor-Configuration
With the gradle plugin version of 1.0.0+ you have to use applicationId as stated in the migration guide
Renamed Properties in ProductFlavors
packageName => applicationId
Thus in your build.gradle you would now use:
productFlavors {
flavor1 {
applicationId "com.example.flavor1"
}
flavor2 {
applicationId "com.example.flavor2"
}
}
From Ethan's answer, both flavorGroups and packageName both are not available anymore. Below works as of March 2015.
android {
...
defaultConfig {
minSdkVersion 8
versionCode 10
}
flavorDimensions "flavor"
productFlavors {
flavor1 {
flavorDimension "flavor"
applicationId "com.example.flavor1"
versionCode 20
}
flavor2 {
flavorDimension "flavor"
applicationId "com.example.flavor2"
minSdkVersion 14
}
}
}
I did not want to use Flavors, so I found a way to do so with buildTypes. I did this by changing my app/build.gradle file as follows:
defaultConfig {
applicationId "com" // See buildTypes.type.applicationIdSuffix
...
}
...
buildTypes {
debug {
applicationIdSuffix ".domain.name.debug"
...
}
releaseStaging {
applicationIdSuffix ".compagny.staging"
...
}
release {
applicationIdSuffix ".domain.name"
...
}
}
This allows me to have 3 apps next to each other on my devices.
I hope this helps others.