web-dev-qa-db-fra.com

Comment vérifier si APK est signé ou "debug build"?

Pour autant que je sache, dans Android "release build" est signé APK. Comment le vérifier à partir du code ou Eclipse a-t-il une sorte de définition secrète?

J'ai besoin de cela pour déboguer les éléments ListView remplis à partir des données de service Web (non, logcat pas une option).

Mes pensées:

  • Applications Android:debuggable, mais pour une raison quelconque, cela ne semble pas fiable.
  • Le codage en dur de l’identifiant de périphérique n’est pas une bonne idée, car j’utilise le même périphérique pour tester les fichiers APK signés.
  • Utiliser le drapeau manuel quelque part dans le code? Plausible, mais j'oublierai définitivement de changer à un moment donné, plus tous les programmeurs sont paresseux.
114
Im0rtality

Il existe différentes manières de vérifier si l'application est construite à l'aide du certificat de débogage ou de version, mais la méthode suivante me semble la meilleure.

Selon les informations contenues dans Android documentation signature de votre application , la clé de débogage contient le nom distinctif suivant: " CN = Débogage Android, O = Android, C = US ". Nous pouvons utiliser ces informations pour vérifier si le paquet est signé avec la clé de débogage sans coder en dur la signature de la clé de débogage dans notre code.

Donné:

import Android.content.pm.Signature;
import Java.security.cert.CertificateException;
import Java.security.cert.X509Certificate;

Vous pouvez implémenter une méthode isDebuggable de cette façon:

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;
}
76
Omar Rehman

Pour vérifier l'indicateur de débogage, vous pouvez utiliser ce code:

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

Kotlin:

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

Pour plus d'informations, veuillez consulter Sécurisation Android Applications LVL .

Sinon, si vous utilisez correctement Gradle, vous pouvez vérifier si BuildConfig.DEBUG est vrai ou faux.

135
Blundell

Répondu par Mark Murphy

La solution la plus simple et la meilleure à long terme, consiste à utiliser BuildConfig.DEBUG. Ceci est une valeur boolean qui sera true pour une construction de débogage, false sinon:

if (BuildConfig.DEBUG) {
  // do something for a debug build
}
130
Xar E Ahmer

Peut-être tard, mais iosched utilise BuildConfig.DEBUG

21
urSus

Si vous voulez vérifier un APK de manière statique, vous pouvez utiliser

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

Cette sortie 0 si le APK n’est pas debuggable et 1 Si c'est.

19
Heath Borders

Ajoutez d'abord ceci à votre fichier build.gradle, cela permettra également l'exécution côte à côte des générations de débogage et de version:

buildTypes {
    debug {
        applicationIdSuffix ".debug"
    }
}

Ajoutez cette méthode:

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

Une version de débogage est également signée, avec une clé différente. Il est généré automatiquement par Eclipse et son certificat est valide pour un an seulement. Quel est le problème avec Android:debuggable? Vous pouvez obtenir cette valeur à partir de code en utilisant PackageManager.

5
Nikolay Elenkov

Une autre option mérite d'être mentionnée. Si vous devez exécuter du code uniquement lorsque le débogueur est connecté, utilisez ce code:

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

Solution dans Kotlin que j'utilise en ce 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
}

de cette façon, je peux toujours me connecter au débogage et ceux-ci seront signalés à Crashlytics (par exemple, pour le processus d'assurance qualité)

0
Rafael Ruiz Muñoz

Résolu avec Android:debuggable. Il y avait un bogue dans la lecture d’élément où, dans certains cas, le drapeau de débogage n’était pas stocké dans l’enregistrement, obtenant if (m.debug && !App.isDebuggable(getContext())) toujours évaluée à false. Ma faute.

0
Im0rtality