How to check if APK is signed or "debug build"?

AndroidDebuggingCertificate

Android Problem Overview


As far as I know, in android "release build" is signed APK. How to check it from code or does Eclipse has some kinda of secret defines?

I need this to debug populating ListView items from web service data (no, logcat not an option).

My thoughts:

  • Application's android:debuggable, but for some reason that doesn't look reliable.
  • Hard-coding device ID isn't good idea, because I am using same device for testing signed APKs.
  • Using manual flag somewhere in code? Plausible, but gonna definitely forget to change at some time, plus all programmers are lazy.

Android Solutions


Solution 1 - Android

To check the debuggable flag, you can use this code:

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

Kotlin:

val isDebuggable = 0 != applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE

For more information, please see Securing Android LVL Applications.

Alternatively, if you're using Gradle correctly, you can check if BuildConfig.DEBUG is true or false.

Solution 2 - Android

Answered by Mark Murphy

The simplest, and best long-term solution, is to use BuildConfig.DEBUG. This is a boolean value that will be true for a debug build, false otherwise:

if (BuildConfig.DEBUG) {
  // do something for a debug build
}

Solution 3 - Android

There are different way to check if the application is build using debug or release certificate, but the following way seems best to me.

According to the info in Android documentation Signing Your Application, debug key contain following subject distinguished name: "CN=Android Debug,O=Android,C=US". We can use this information to test if package is signed with debug key without hardcoding debug key signature into our code.

Given:

import android.content.pm.Signature;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

You can implement an isDebuggable method this way:

private static final X500Principal DEBUG_DN = new X500Principal("CN=Android Debug,O=Android,C=US");
private boolean isDebuggable(Context ctx)
{
    boolean debuggable = false;
 
    try
    {
        PackageInfo pinfo = ctx.getPackageManager().getPackageInfo(ctx.getPackageName(),PackageManager.GET_SIGNATURES);
        Signature signatures[] = pinfo.signatures;

        CertificateFactory cf = CertificateFactory.getInstance("X.509");
     
        for ( int i = 0; i < signatures.length;i++)
        {   
            ByteArrayInputStream stream = new ByteArrayInputStream(signatures[i].toByteArray());
            X509Certificate cert = (X509Certificate) cf.generateCertificate(stream);       
            debuggable = cert.getSubjectX500Principal().equals(DEBUG_DN);
            if (debuggable)
                break;
        }
    }
    catch (NameNotFoundException e)
    {
        //debuggable variable will remain false
    }
    catch (CertificateException e)
    {
        //debuggable variable will remain false
    }
    return debuggable;
}

Solution 4 - Android

If you want to check an APK statically, you could use

aapt dump badging /path/to/apk | grep -c application-debuggable

This outputs 0 if the APK isn't debuggable and 1 if it is.

Solution 5 - Android

Maybe late, but iosched uses BuildConfig.DEBUG

Solution 6 - Android

First add this to your build.gradle file, this will also allow side by side running of debug and release builds:

buildTypes {
    debug {
        applicationIdSuffix ".debug"
    }
}

Add this method:

public static boolean isDebug(Context context) {
    String pName = context.getPackageName();
    if (pName != null && pName.endsWith(".debug")) {
        return true;
    } else {
        return false;
    }
}

Solution 7 - Android

A debug build is signed as well, just with a different key. It's generated automatically by Eclipse, and its certificate is valid for one year only. What's the problem with android:debuggable? You can get this value from code using PackageManager.

Solution 8 - Android

Another option, worth mentioning. If you need to execute some code only when debugger is attached, use this code:

if (Debug.isDebuggerConnected() || Debug.waitingForDebugger()) { 
    //code to be executed 
}

Solution 9 - Android

Solved with android:debuggable. It was bug in reading item where in some cases debug flag on item was not being stored in record getting if (m.debug && !App.isDebuggable(getContext())) always evaluated to false. My bad.

Solution 10 - Android

Solution in Kotlin that I'm using at the moment:

@SuppressLint("PackageManagerGetSignatures")
@Suppress("DEPRECATION")
fun isSigned(context: Context?): Boolean {
    return (context?.packageManager?.getPackageInfo(context.packageName, PackageManager.GET_SIGNATURES)?.signatures?.firstOrNull()?.toByteArray()
            ?.let {
                return@let CertificateFactory.getInstance("X.509").generateCertificate(ByteArrayInputStream(it))
            } as? X509Certificate)
            ?.issuerDN
            ?.name
            ?.contains("O=Android", ignoreCase = false) ?: true
}

that way I can still SIGN in debug and those will be reported to Crashlytics (example, for the QA process)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionIm0rtalityView Question on Stackoverflow
Solution 1 - AndroidBlundellView Answer on Stackoverflow
Solution 2 - AndroidZar E AhmerView Answer on Stackoverflow
Solution 3 - AndroidOmar RehmanView Answer on Stackoverflow
Solution 4 - AndroidHeath BordersView Answer on Stackoverflow
Solution 5 - AndroidurSusView Answer on Stackoverflow
Solution 6 - AndroidMeanmanView Answer on Stackoverflow
Solution 7 - AndroidNikolay ElenkovView Answer on Stackoverflow
Solution 8 - AndroidIgor GorjancView Answer on Stackoverflow
Solution 9 - AndroidIm0rtalityView Answer on Stackoverflow
Solution 10 - AndroidRafael Ruiz MuñozView Answer on Stackoverflow