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

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

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

Мои мысли:

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

9 ответов

Решение

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

Согласно информации в документации 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;
}

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

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

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

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

Ответ Марком Мерфи

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

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

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

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

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

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

Сначала добавьте это в свой файл 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;
    }
}

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

Еще один вариант, заслуживающий упоминания. Если вам нужно выполнить какой-то код только при подключенном отладчике, используйте этот код:
if (Debug.isDebuggerConnected() || Debug.waitingForDebugger()) { //code to be executed }

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

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

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

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

Другие вопросы по тегам