Distinguishing development mode and release mode environment settings on Android
-
20-09-2019 - |
Question
I'm building an Android application and would like to maintain a few environment variables that I can tweak depending on whether I'm in development mode or release mode. For example, I need to invoke a web service and the URL will be slightly different in either mode. I'd like to externalize this and other settings so I can change them easily based on my target deployment.
Are there any best practices or anything in the SDK to assist with this need?
Solution
According to this stackoverflow post, in SDK Tools version 17 (we're on 19 as of this writing) adds a BuildConfig.DEBUG
constant that is true when building a dev build.
OTHER TIPS
The following solution assumes that in manifest file you always set android:debuggable=true
while developing and android:debuggable=false
for application release.
Now you can check this attribute's value from your code by checking the ApplicationInfo.FLAG_DEBUGGABLE
flag in the ApplicationInfo
obtained from PackageManager
.
The following code snippet could help:
PackageInfo packageInfo = ... // get package info for your context
int flags = packageInfo.applicationInfo.flags;
if ((flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
// development mode
} else {
// release mode
}
@viktor-bresan Thanks for a useful solution. It'd be more helpful if you just included a general way to retrieve the current application's context to make it a fully working example. Something along the lines of the below:
PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
Android build.gradle has Handles Debug and Release Environment well.
Append the following code snippet in build.gradle
file
buildTypes {
debug {
buildConfigField "Boolean", "IS_DEBUG_MODE", 'true'
}
release {
buildConfigField "Boolean", "IS_DEBUG_MODE", 'false'
}
}
Now you can access the variable like below
if (BuildConfig.IS_DEBUG_MODE) { {
//Debug mode.
} else {
//Release mode
}
I would check out isDebuggerConnected
How about something like the code below ...
public void onCreate Bundle b ) {
super.onCreate(savedInstanceState);
if ( signedWithDebugKey(this,this.getClass()) ) {
blah blah blah
}
blah
blah
blah
}
static final String DEBUGKEY =
"get the debug key from logcat after calling the function below once from the emulator";
public static boolean signedWithDebugKey(Context context, Class<?> cls)
{
boolean result = false;
try {
ComponentName comp = new ComponentName(context, cls);
PackageInfo pinfo = context.getPackageManager().getPackageInfo(comp.getPackageName(),PackageManager.GET_SIGNATURES);
Signature sigs[] = pinfo.signatures;
for ( int i = 0; i < sigs.length;i++)
Log.d(TAG,sigs[i].toCharsString());
if (DEBUGKEY.equals(sigs[0].toCharsString())) {
result = true;
Log.d(TAG,"package has been signed with the debug key");
} else {
Log.d(TAG,"package signed with a key other than the debug key");
}
} catch (android.content.pm.PackageManager.NameNotFoundException e) {
return false;
}
return result;
}
I came across another approach today by accident that seems really straight forward.. Look at Build.TAGS, when the app is created for development this evaluates to the String "test-keys".
Doesn't get much easier than a string compare.
Also Build.MODEL and Build.PRODUCT evaluate to the String "google_sdk" on the emulator!
Here's the method I use:
http://whereblogger.klaki.net/2009/10/choosing-android-maps-api-key-at-run.html
I use it to toggle debug logging and the maps API key.