Change constant values when building a release edition - android

I'm developing in eclipse using ADT for android.
In my application I have some constants which help me to to debug my app easily.
As an example I have:
public static final boolean DEBUG_TOAST_LOGS = true;
which help me to toast some logs on the screen.
Each time I intend to build a release, I have to go through my
constants and set their values to what is appropriate for the release edition, which is somehow painful.
Now what I want is a way to build my app, using two configurations: one for debug mode and the other for release mode. The release mode should set my constants to the appropriate values. How cant I do that? What's your suggestion? What's the best way to accomplish my need?
Any help would be appreciated.

I'm not sure if you are using Gradle as your build system. If you do, you can set build-type specific resources, e.g. a boolean debug value will be true for debug build type, and false for release build type.
build.gradle
android {
defaultConfig {
...
resValue "bool", "debug", "true"
}
buildTypes {
release {
...
resValue "bool", "debug", "false"
}
}
...
}
Application.java
public class Application extends android.app.Application {
#Override
public void onCreate() {
super.onCreate();
if (getResources().getBoolean(R.bool.debug)) {
... // debug logic here
}
...
}
}

#hidro's solution is fine, but requires an unnecessary getResources()... call each time you want to access the value.
There's another possibility :
build.gradle
android {
buildTypes {
debug {
buildConfigField "boolean", "DEBUG_TOAST_LOGS", "true"
}
release {
buildConfigField "boolean", "DEBUG_TOAST_LOGS", "false"
}
}
}
Then,in your code, you can write :
if (BuildConfig.DEBUG_TOAST_LOGS) {
// ... enjoy your toasts ...
}

Related

Link Firebase for each build types

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 ...

BuildConfigField mock for unit test in Kotlin

I'm trying to cover as much as possible a Kotlin Android library and I'm encountering an issue about custom BuildConfig variable, better known as buildConfigField.
I would like to mock this variable to test both true and false values.
Extract from Gradle file :
android {
defaultConfig {
buildConfigField "boolean", "ENABLE_LOG", "false"
}
flavorDimensions "log"
productFlavors {
loggable {
buildConfigField "boolean", "ENABLE_LOG", "true"
dimension "log"
}
notloggable {
dimension "log"
}
}
}
Extract of the Kotlin function to be tested :
fun buildClient(): MyClient {
var myClientBuilder : MyClient.Builder = MyClient.Builder();
if (BuildConfig.ENABLE_LOG) {
val interceptor = LoggingInterceptor();
interceptor.setLevel(LoggingInterceptor.Level.ALL);
myClientBuilder.addInterceptor(interceptor);
}
return myClientBuilder.build()
}
Unit test :
#Test
fun buildClient_enableLog_oneInterceptor() {
// GIVEN
Mockito.mock(BuildConfig::class.java)
Mockito.doReturn(true).`when`(BuildConfig.ENABLE_LOG)
// WHEN
val myClient = myService!!.buildClient()
// THEN
assertNotNull(myClient)
assertNotNull(myClient.interceptors())
assertEquals(1, myClient.interceptors().size)
}
I tried different things and it never works.
If someone have already done this work, it can help me a lot (and others I guess).
Thanks
ReflectionHelpers.setStaticField(BuildConfig::class.java, "ENABLE_LOG", true)
By default, all tests run against the debug build type. You can change this to another build type by using the testBuildType property in your module-level build.gradle file. For example, if you want to run your tests against your "staging" build type, edit the file as shown in the following snippet.
android {
...
testBuildType "staging"
}
but this is causing other options to fail
Little late to the party but this is how you should test any thing related to BuildConfig file.
BuildConfig.java is generated for each variant of your app. In your case you have atleast 4 variants.
LoggableDebug
LoggableRelease
NotloggableDebug
NotloggableRelease
ENABLE_LOG will be false for options 3 and 4.
If you want to Unit test this, I recommend writing UnitTest in src/testNotLoggable/java/com/.../TestFile.java.
In that TestFile.java your BuildConfig.ENABLE_LOG should be false.
You can check BuildConfig.java file for each variant under /build/source/buildConfig/flavorname/debug/com/project/../BuildConfig.java

Can "testBuildType" be conditional in build.gradle file of Android project?

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.

Android using Gradle Build flavors in the code like an if case

I'm trying to work with build flavors. In my build.gradle I've defined 2 flavors, a normal flavor and an admin flavor.
Basicly, the admin flavor has an extra button on the main activity.
I understand that I can define different packages/classes for different flavors. But is there a way to make a sort of if case to add/remove a piece of code depending on the flavor?
Basicly, I would need two versions of an Activity. But I don't want two entire different versions of the activity and maintain them.
So in my activity I would like to do
=> gradle check if flavor is 'admin'
=> if yes, add this code of the button
Is this possible? Or would you need two different physical activities and thus maintain both of them when you add functionality afterwards.
BuildConfig.FLAVOR gives you combined product flavor.
So if you have only one flavor dimension:
productFlavors {
normal {
}
admin {
}
}
Then you can just check it:
if (BuildConfig.FLAVOR.equals("admin")) {
...
}
But if you have multiple flavor dimensions:
flavorDimensions "access", "color"
productFlavors {
normal {
dimension "access"
}
admin {
dimension "access"
}
red {
dimension "color"
}
blue {
dimension "color"
}
}
there are also BuildConfig.FLAVOR_access and BuildConfig.FLAVOR_color fields so you should check it like this:
if (BuildConfig.FLAVOR_access.equals("admin")) {
...
}
And BuildConfig.FLAVOR contains full flavor name. For example, adminBlue.
To avoid plain string in the condition, you can define a boolean property:
productFlavors {
normal {
flavorDimension "access"
buildConfigField 'boolean', 'IS_ADMIN', 'false'
}
admin {
flavorDimension "access"
buildConfigField 'boolean', 'IS_ADMIN', 'true'
}
}
Then you can use it like this:
if (BuildConfig.IS_ADMIN) {
...
}
You can define either different build configuration fields or different resource values (like string values) per flavor, e.g. (as per Google's gradle tips and recipes), e.g.,
android {
...
buildTypes {
release {
// These values are defined only for the release build, which
// is typically used for full builds and continuous builds.
buildConfigField("String", "BUILD_TIME", "\"${minutesSinceEpoch}\"")
resValue("string", "build_time", "${minutesSinceEpoch}")
...
}
debug {
// Use static values for incremental builds to ensure that
// resource files and BuildConfig aren't rebuilt with each run.
// If they were dynamic, they would prevent certain benefits of
// Instant Run as well as Gradle UP-TO-DATE checks.
buildConfigField("String", "BUILD_TIME", "\"0\"")
resValue("string", "build_time", "0")
}
}
}
So in this case, something like
productFlavors {
normal {
dimension "access"
buildConfigField("boolean", "IS_ADMIN", "false")
}
admin {
dimension "access"
buildConfigField("boolean", "IS_ADMIN", "true")
}
}
and then use it like
if (BuildConfig.IS_ADMIN) {
...
} else {
...
}
or if it is just to have different string values for different flavors, it can be done with different resValues and then you don't even need the if/then
You can try this way
productFlavors {
def app_name = "you app name"
development {
versionCode 1
versionName "1.0.1"
buildConfigField 'String', 'varibalename', ""
}
release {
versionCode 1
versionName "1.0.1"
buildConfigField 'String', 'varibalename', ""
}
}
if(BuildConfig.varibalename){}

Different API Host with gradle and android

I was wondering if it is possible to provide a different API Host per build using gradle. Ideally I would like to access the constant through my code the same so when I do a gradle build, it builds the release.apk to point to http://example.com and the debug.apk to point to http://debug.example.com.
I have achieved this using the following:
buildTypes {
debug {
buildConfig "public final static String API_HOST = \"http://debug.example.com\";"
}
release {
buildConfig "public final static String API_HOST = \"https://example.com\";"
}
}
However that seems pretty dirty
Cheers
I think a better alternative with today's Gradle features is to specify both productFlavors and buildTypes (example below).
The buildTypes control what certificate I sign with, and whether Proguard is run.
The productFlavors control the intended environment, which includes custom resources, as well as a different package name so I can install them both side by side.
Then I configure my server address in strings.xml for each variant and load it at runtime.
src/dev/res/values/strings.xml
src/staging/res/values/strings.xml
strings.xml example from the "dev" variant:
<string name="config_url">http://com.example.debug</string>
build.gradle snippet:
productFlavors {
dev {
packageName "com.example.dev"
}
staging {
packageName "com.example.staging"
}
}
buildTypes {
debug {
versionNameSuffix " debug"
signingConfig signingConfigs.debug
}
release {
// A release build runs Proguard, and signs with a release certificate
zipAlign true
runProguard true
proguardFile 'proguard-project.txt'
proguardFile getDefaultProguardFile('proguard-android-optimize.txt')
signingConfig signingConfigs.release
}
}
An alternative is to use buildConfigField:
buildTypes {
debug {
buildConfigField 'String', 'API_HOST', '"https://debug.example.com"'
}
release {
buildConfigField 'String', 'API_HOST', '"https://example.com"'
}
}
You would then refer to it in your code via BuildConfig.API_HOST
So I ended up speaking to one of the gradleware engineers about this.... My initial solution is the correct way. Google/Gradle will be improving this in the future.
To add multiple values you separate the the strings with comas.

Categories

Resources