Как проверить, подписана ли APK или "отладить сборку"?

Насколько я знаю, в андроидном "релиз-сборке" подписан APK. Как проверить его с помощью кода или определяет ли Eclipse какой-то секрет?

Мне нужно это для отладки заполнения элементов ListView из данных веб-службы (нет, logcat не опция).

Мои мысли:

  • Приложение android:debuggable, но по какой-то причине оно не выглядит надежным.
  • Идентификатор жесткого диска не является хорошей идеей, потому что я использую одно и то же устройство для тестирования подписанных APK.
  • Использование флага вручную в коде? Правдоподобно, но определенно забудьте изменить в какой-то момент, плюс все программисты ленивы.

Ответ 1

Существует другой способ проверить, работает ли приложение с использованием сертификата отладки или выпуска, но мне кажется, что следующий способ выглядит лучше.

Согласно информации в документации для Android Подписывание вашего приложения, ключ отладки содержит следующее имя различающегося имени: " CN = Android Debug, O = Android, C = US". Мы можем использовать эту информацию, чтобы проверить, подписан ли пакет с помощью отладочного ключа без подписи ключа отладки в коде.

Дано:

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

Вы можете реализовать метод isDebuggable следующим образом:

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;
}

Ответ 2

Чтобы проверить флаг отладки, вы можете использовать этот код:

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

Котлин:

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

Для получения дополнительной информации см. Защита приложений Android LVL.

Кроме того, если вы используете Gradle правильно, вы можете проверить, является ли BuildConfig.DEBUG истинным или ложным.

Ответ 3

Отвечено Марк Мерфи

Простейшим и лучшим долгосрочным решением является использование BuildConfig.DEBUG. Это значение boolean, которое будет true для сборки отладки, false иначе:

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

Ответ 4

Возможно, поздно, но iosched использует BuildConfig.DEBUG

Ответ 5

Если вы хотите статически ставить APK, вы можете использовать

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

Это выводит 0, если APK не отлаживается и 1, если оно есть.

Ответ 6

Сначала добавьте это в свой файл build.gradle, это также позволит работать сбоку отладки и выпуска: бок о бок:

buildTypes {
    debug {
        applicationIdSuffix ".debug"
    }
}

Добавьте этот метод:

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

Ответ 7

Отладочная сборка также подписана, просто с другим ключом. Он автоматически генерируется Eclipse, и его сертификат действителен только один год. Какая проблема с android:debuggable? Вы можете получить это значение из кода с помощью PackageManager.

Ответ 8

Еще один вариант, заслуживающий упоминания. Если вам нужно выполнить какой-то код только при подключенном отладчике, используйте этот код:

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

Ответ 9

Решено с помощью android:debuggable. Это была ошибка при чтении элемента, где в некоторых случаях флаг отладки на элементе не сохранялся в записи, получая if (m.debug && !App.isDebuggable(getContext())), всегда оцениваемый до false. Мой плохой.

Ответ 10

Решение в Kotlin, которое я использую на данный момент:

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

таким образом, я все еще могу ПОДПИСАТЬСЯ в отладке, и они будут сообщены Crashlytics (например, для процесса QA)