Як перевірити, чи підписано APK або "побудувати налагодження"?


121

Наскільки я знаю, в андроїд "build release" підписаний APK. Як перевірити це за допомогою коду чи у Eclipse є якесь таємне визначення?

Мені потрібно це, щоб налагодити заповнення елементів ListView з даних веб-служб (ні, logcat не є варіантом).

Мої думки:

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

Відверта редакція Філа. Це не питання про те, чи програма легально розподіляється по ринку чи ні. Справа в тому, чи програма в нерухомому режимі налагодження.
Im0rtality

Цей спосіб найпростіший для цього: stackoverflow.com/a/23844716/2296787
MBH

Відповіді:


80

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

Відповідно до інформації в документації для 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;
}

6
Для того, щоб допомогти в рішенні декількох паросочетание імпорту, класи , використовувані тут java.security.cert.X509Certificate, java.security.cert.CertificateExceptionі android.content.pm.Signature. Усі інші класи для мене не представляють кількох матчів
Крістіан Гарсія

1
Відредагована відповідь із цим імпортом. Дякую!
Cory Petosky

чи достатньо ефективний запуск методу onCreate класу додатків?
андроїд розробник

Я не зазначив часу виконання, але я використовував його у своєму додатку і не маю жодних проблем із ефективністю.
Омар Рехман

Результат може бути кешований для ефективності.
ftvs

138

Щоб перевірити прапор, що налагоджується, ви можете використовувати цей код:

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

Котлін:

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

Для отримання додаткової інформації див. Захист додатків Android LVL .

Крім того, якщо ви правильно використовуєте Gradle, ви можете перевірити, чи BuildConfig.DEBUGправда чи неправда.


здається, що це все-таки перевіряє андроїд маніфесту: налагодження
xster

2
Перший тест на Manifest, який виводиться з ладу, це застаріло. Другий неможливий для бібліотек, у lib буде власний BuildConfig - не в змозі імпортувати BuildConfig програми, який використовує Lib. Тому помічена відповідь - «добре»
Крістоф

Ця відповідь буде працювати у всіх випадках незалежно від проекту бібліотеки чи проекту програми.
Lavekush Agrawal

131

Відповів Марк Мерфі

Найпростішим і найкращим довгостроковим рішенням є використання BuildConfig.DEBUG. Це booleanзначення, яке буде trueрозроблено для налагодження, falseінакше:

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

8
Єдиним недоліком такого підходу є те, що він не працюватиме в бібліотечних проектах (aar's). Коли бібліотеки побудовані, це призведе до помилки, тому навіть якщо програма, яка використовує бібліотеку, знаходиться в режимі налагодження, ця перевірка призведе до помилки в коді бібліотеки.
Віто Андоліні

24

Якщо ви хочете перевірити APKстатично, ви можете використовувати

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

Це виводиться, 0якщо APKвін не піддається відладці і 1якщо він є.


3
це єдине рішення, для перевірки остаточного apk. Інші відповіді передбачають, що у вас є джерело.
Гільєрмо Тобар

1
aaptтут живе/Users/USER_NAME/library/Android/sdk/build-tools/28.0.3/aapt
Кейсі

21

Можливо, із запізненням, але іонізовані BuildConfig.DEBUG


тепер це безпечно у використанні? є стаття, яка говорить про те, що у неї є деякі проблеми: digipom.com/be-careful-with-buildconfig-debug
андроїд розробник

Це найкраща відповідь!
Пітер Фортуін

ні, якщо ви пишете сторонні бібліотеки і не знаєте пакет BuildConfig під час компіляції.
Сем Дозор

Сем, ти можеш детальніше розглянути це?
Агамемнус

10

Спочатку додайте це у файл 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;
    }
}

1
Я віддаю перевагу цій відповіді, тому що вона достовірна. Мені потрібно було додати новий "дозволений додаток для Android" до мого ключа API Google Maps (оскільки ідентифікатор програми інший).
Баз

5

Збірка налагодження також підписана, просто з іншим ключем. Він генерується автоматично Eclipse, і його сертифікат дійсний протягом одного року. У чому проблема android:debuggable? Ви можете отримати це значення за допомогою коду, використовуючи PackageManager.


3

Ще один варіант, варто згадати. Якщо вам потрібно виконати якийсь код лише тоді, коли доданий налагоджувач, використовуйте цей код:

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

0

Вирішено с android:debuggable. Це була помилка в читанні елемента, коли в деяких випадках прапор налагодження на елементі не зберігався в записі, отримуючи if (m.debug && !App.isDebuggable(getContext()))завжди оцінку false. Моє ліжко.


13
Я усвідомлюю, що це вже більше року, проте ви повинні прийняти відповідь @Omar Rehman, а не цю. Хоча те, що ви опублікували, це те, що ви в кінцевому підсумку зробили, воно насправді не відповідає на поставлене вами запитання, в той час як рішення Омара, здається, це робить, тобто він заслуговує на прийнятий кредит.
мак

7
@Mah - зовсім недоречно знущати когось за те, що він не прийняв відповідь, яка була розміщена майже через рік після того, як вони самі вирішили свою проблему! І це навіть ігнорування того, наскільки складнішою є відповідь, яку ви номінуєте, ніж відповідь, з яким вони пішли, - що насправді відповідає на поставлене запитання, оскільки питання викликає помилка, що призводить до помилкового враження, що прапор недостовірний .
Кріс Страттон

4
@ChrisStratton, якщо ти вважаєш, що моя відповідь була знущанням, я думаю, ти мало читаєш Інтернет. Я підтримую ваше право розміщувати вашу протилежну точку зору в коментарі, як і ви, і в результаті я переглянув свій коментар та інші публікації в цьому запитанні, і я стою під своїм оригінальним коментарем: плакат задав питання, яке було законним і правильно відповів хтось. Виходячи з власної "відповіді", його первісне запитання - це не те, що він хотів задати, в першу чергу ... підпис APK (реліз або налагодження) має абсолютно нульовий вплив на маніфест.
ма

3
@mah - вирішувати питання, що задовольняє їхню фактичну потребу в застосуванні, вирішуватимете не ви , а також, якщо відмінність, яку ви зробите, має одне значення - або, як очевидно в цьому випадку, ні. Що ще важливіше, ви повністю не помічаєте, що відповідь, яку ви запропонували, була опублікована майже через рік після задоволення фактичної потреби . Хтось карає за те, що більш ніж через рік не повертався, щоб змінити свою згоду, що є знущанням.
Кріс Страттон

3
@ChrisStratton запитувачеві потрібно також задати фактичне запитання, на яке він хоче відповісти - те, що в цьому випадку не було зроблено. Ви вірні, що я не помітив, коли була зроблена відповідь, яка насправді відповідає тому, що було розміщено, проте покарання взагалі немає, є лише розумне вираження моєї думки. Якщо ви думаєте, що я тут є хуліганом, я наполегливо прошу вас відмітити мій коментар за зловживання. Перш ніж це робити, ви можете ознайомитись зі своїми публікаціями тут.
ма

0

Рішення в Котліні, яке я зараз використовую:

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.