Tek Eye Logo

Tek Eye

Android Debug Vs Release Build Check in Running Code

An Android app will execute in debug mode in the development environment, i.e. while running in the Android Studio Integrated Development Environment (IDE). The app will execute in release mode when installed from Google Play. In release mode any debug logging, StrictMode, and the debugging option must be disabled. When developing an Android app there are occasional times when detecting debug mode vs release mode is helpful. This article contains example code to show how debug mode and release mode can be determined at app runtime.

Android Logo

Distinguishing Android Debug Mode Vs Release Mode

It is possible to wrap calls to logging code, and StrictMode set up, in code that checks for debug mode. To detect Android debug vs release mode there are two objects that expose the debug flag, the ApplicationInfo class (since API Level 1) and BuildConfig (subsequent SDK releases).

(For this Android tutorial try the given code in a simple app. This article assumes that the latest Android Studio is installed, a basic app can be created and run (here called Check Debuggable), and the code in this article can be correctly copied into Android Studio. The example code can be changed to meet your own requirements. When entering code in Studio add import statements when prompted by pressing Alt-Enter.)

Android Debug vs Release Using ApplicationInfo Flags

With ApplicationInfo the flags field has a debug bit. To use it in code perform a boolean And on flags with ApplicationInfo.FLAG_DEBUGGABLE, if the result is not zero the app is in debug mode (getApplicationInfo() is available from Context):

boolean InDebug=(getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE)!=0;

The Old Way of Overriding the Android Debug Flag

The debug bit used to be set via the android:debuggable attribute on the application element in AndroidManifest.xml (use the Studio Project explorer to find AndroidManifest.xml). Usually the android:debuggable attribute was not present, it was set automatically by the build tools. Being set true to allow the app to be debugged in the IDE, and set to false to turn off debugging when the final Android app's APK was generated. Therefore, it used to be possible to force debug mode on or off by setting it true or false in the manifest file:

<application
        android:debuggable="false"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        ...

However, that not longer appears to work. Now if android:debuggable is explicitly set then Studio will display a warning:

Avoid hardcoding the debug mode; leaving it out allows debug and release builds to automatically assign one

It's best to leave out the android:debuggable attribute from the manifest. If you do, then the tools will automatically insert android:debuggable=true when building an APK to debug on an emulator or device. And when you perform a release build, such as Exporting APK, it will automatically set it to false. If on the other hand you specify a specific value in the manifest file, then the tools will always use it.

This can lead to accidentally publishing your app with debug information.

But developers on some forums now say that the android:debuggable attribute no longer works. Indeed, if set to a different value from the Gradle settings (see below) the project will not build.

Android Debug vs Release Using BuildConfig.DEBUG

The class BuildConfig (generated at build time) allows for build specific settings. The flag BuildConfig.DEBUG is set true when the app is running in the IDE. It is set false in the released APK, therefore BuildConfig.DEBUG mirrors the older android:debuggable value.

To explicitly set BuildConfig.DEBUG edit the build.gradle for the app module, here turning off debugging in the IDE for the normal debug build:

release {
    minifyEnabled false
    proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug {
    debuggable false
}

Why would you want to explicitly set debuggable to true or false? It could be used when testing an app on an Android Virtual Device (AVD) or real device close to a release. Set to false to check that a release build is not unnecessarily producing log output, or displaying test data or screens. Likewise, set it to true when loading an APK on a physical device to provide extra functionality to testers (e.g. provide an easy way to get to extra levels in a game app). However, if explicitly set the debuggable setting should always be deleted before the final shipping build, i.e. this would not be a good setting in a released APK:

release {
    debuggable true
    minifyEnabled false
    proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}

Example Code to Check for Android Debug Vs Release Mode

Here is the simple layout used for the code that follows:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.checkdebuggable.MainActivity">
    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="ApplicationInfo.FLAG_DEBUGGABLE bit is set:"
        android:textAppearance="?android:attr/textAppearanceMedium" />
    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/textView1"
        android:layout_marginTop="20dp"
        android:text="UNKNOWN"
        android:textAppearance="?android:attr/textAppearanceLarge" />
    <TextView
        android:id="@+id/textView3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/textView2"
        android:layout_marginTop="20dp"
        android:text="BuildConfig.DEBUG is set:"
        android:textAppearance="?android:attr/textAppearanceMedium" />
    <TextView
        android:id="@+id/textView4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/textView3"
        android:layout_marginTop="20dp"
        android:text="UNKNOWN"
        android:textAppearance="?android:attr/textAppearanceLarge" />
</RelativeLayout>

It has already been seen that the app's ApplicationInfo instance is read from the app's Context:

ApplicationInfo appInfo = getApplicationInfo();

Which is the same as ApplicationInfo appInfo = this.getApplicationInfo(); when in the activity class. Note however, that prior to Cupcake (API level 3) ApplicationInfo needed to be obtained from the PackageManager:

ApplicationInfo appInfo;
try {
    appInfo = getPackageManager().getApplicationInfo(getPackageName(), 0);
} catch (Exception e) {
    e.printStackTrace();
}

Using a reference to the app's ApplicationInfo the flags value can be tested for the debug setting. Here it is being used to update a TextView:

if(appInfo!=null) {
    if( (appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0)
        ((TextView)findViewById(R.id.textView2)).setText("TRUE");
    else
        ((TextView)findViewById(R.id.textView2)).setText("FALSE");
}

And the code to read BuildConfig.DEBUG:

if(BuildConfig.DEBUG) {
    ((TextView)findViewById(R.id.textView4)).setText("TRUE");
} else {
    ((TextView)findViewById(R.id.textView4)).setText("FALSE");
}

Here's the debugging settings in action. First no debuggable setting is present and the code is running in the IDE:

Android Debug Vs Release IDE Values

The same code running in a signed APK:

Android Debug Vs Release APK Values

And now running from the IDE with the debuggable flag manually set to false

Android Debug Vs Release APK Values

Here is the full MainActivity.java code:

package com.example.checkdebuggable;

import android.app.Activity;
import android.content.pm.ApplicationInfo;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if( (getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0)
            ((TextView)findViewById(R.id.textView2)).setText("TRUE");
        else
            ((TextView)findViewById(R.id.textView2)).setText("FALSE");

        if(BuildConfig.DEBUG) {
            ((TextView)findViewById(R.id.textView4)).setText("TRUE");
        } else {
            ((TextView)findViewById(R.id.textView4)).setText("FALSE");
        }
    }
}

In Summary

To detect if code is running in debug test the BuildConfig.DEBUG for true. However, a word of warning. BuildConfig.DEBUG may not be correct if checked in code packaged in a library.

See Also

Author:  Published:  Updated:  

ShareSubmit to TwitterSubmit to FacebookSubmit to Google+Submit to LinkedInSubmit to redditPrint Page

markdown CMS Small Logo Icon ↓markdown↓ CMS is fast and simple. Build websites quickly and publish easily. For beginner to expert.



Articles on:

Android Programming and Android Practice Projects, HTML, VPS, Computing, IT, Computer History, ↓markdown↓ CMS, C# Programming, Using Windows for Programming



Free Android Projects and Samples:

Android Examples, Android List Examples, Android UI Examples