APK imzalı mı yoksa "hata ayıklama derlemesi" mi kontrol edilir?


121

Bildiğim kadarıyla, android'de "sürüm yapısı" imzalı APK'dir. Koddan nasıl kontrol edilir veya Eclipse'in bir tür gizli tanımları var mı?

Buna, ListView öğelerini web hizmeti verilerinden doldururken hata ayıklamak için ihtiyacım var (hayır, logcat bir seçenek değil).

Düşüncelerim:

  • Uygulama android:debuggable, ancak bazı nedenlerden dolayı güvenilir görünmüyor.
  • Cihaz kimliğini sabit kodlamak iyi bir fikir değil çünkü imzalı APK'ları test etmek için aynı cihazı kullanıyorum.
  • Kodun herhangi bir yerinde manuel bayrak mı kullanıyorsunuz? Makul, ancak bir ara kesinlikle değişmeyi unutacak, ayrıca tüm programcılar tembel.

Geri alınan Phil'in düzenlemesi. Bu, programın yasal olarak pazara dağıtılması veya dağıtılmaması ile ilgili bir soru değildir. Sorun, program hala "hata ayıklama modunda" mı?
Im0rtality

Bu, bunu yapmanın en kolay yoludur: stackoverflow.com/a/23844716/2296787
MBH

Yanıtlar:


80

Uygulamanın hata ayıklama veya sürüm sertifikası kullanılarak oluşturulup oluşturulmadığını kontrol etmenin farklı yolları vardır, ancak aşağıdaki yol bana en iyi şekilde görünmektedir.

Uygulamanızı İmzalama Android belgelerinde yer alan bilgilere göre , hata ayıklama anahtarı şu konu ayırt edici adını içerir: " CN = Android Debug, O = Android, C = US ". Bu bilgileri, paketin hata ayıklama anahtarı imzasını kodumuza kodlamadan hata ayıklama anahtarı ile imzalanıp imzalanmadığını test etmek için kullanabiliriz.

Verilen:

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

İsDebuggable yöntemini şu şekilde uygulayabilirsiniz:

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
Birden fazla içe aktarma eşleşmesini çözmeye yardımcı olmak için java.security.cert.X509Certificate, burada kullanılan sınıflar , java.security.cert.CertificateExceptionve android.content.pm.Signature. Diğer tüm sınıflar benim için birden fazla maç
sunmuyor

1
Bu içe aktarmalarla yanıt düzenlenmiştir. Teşekkürler!
Cory Petosky

uygulama sınıfının onCreate yöntemi üzerinde çalıştırılacak kadar verimli mi?
android geliştiricisi

Yürütme zamanını not etmedim, ancak bunu uygulamamda kullanıyorum ve verimlilikle ilgili herhangi bir sorunum yok.
Ömer Rehman

Sonuç, verimlilik için önbelleğe alınabilir.
ftvs

138

Hata ayıklanabilir bayrağını kontrol etmek için şu kodu kullanabilirsiniz:

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

Kotlin:

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

Daha fazla bilgi için lütfen Android LVL Uygulamalarının Güvenliğini Sağlama bölümüne bakın .

Alternatif olarak, Gradle'ı doğru kullanıyorsanız BuildConfig.DEBUG, doğru mu yanlış mı olduğunu kontrol edebilirsiniz .


Görünüşe göre bu hala manifestin android:
debuggable

2
İlki Manifest debugable'ı test ediyor, bu kullanımdan kaldırıldı. İkincisi, kütüphaneler için mümkün değildir, kütüphanenin kendi BuildConfig'i olacaktır - Lib'i kullanan Uygulamanın BuildConfig'ini içe aktaramayacaktır. Bu nedenle işaretli cevap "tamam"
Christoph

Bu cevap, kütüphane projesinden veya uygulama projesinden bağımsız olarak her durumda işe yarayacaktır.
Lavekush Agrawal

131

Yanıtlayan Mark Murphy

En basit ve en iyi uzun vadeli çözüm kullanmaktır BuildConfig.DEBUG. Bu, bir hata ayıklama derlemesi için booleanolacak bir değerdir true, falseaksi takdirde:

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

8
Bu yaklaşımın tek dezavantajı, kütüphane projelerinde (aar) çalışmamasıdır. Kitaplıklar oluşturulduğunda, bu false ile sonuçlanacaktır, bu nedenle kitaplığı kullanan bir uygulama hata ayıklama modunda olsa bile, bu kontrol kütüphane kodu içinde false ile sonuçlanacaktır.
Vito Andolini

24

APKStatik olarak kontrol etmek istiyorsanız, kullanabilirsiniz

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

Bu çıkışlar 0ise APKdebuggable değildir ve 1o ise.


3
son apk üzerinden doğrulama yapmak için tek çözüm budur. Diğer yanıtlar kaynağa sahip olduğunuzu varsayar.
Guillermo Tobar

1
aaptburada yaşıyor/Users/USER_NAME/library/Android/sdk/build-tools/28.0.3/aapt
Casey


10

Önce bunu build.gradle dosyanıza ekleyin, bu aynı zamanda hata ayıklama ve sürüm yapılarının yan yana çalıştırılmasına da izin verecektir:

buildTypes {
    debug {
        applicationIdSuffix ".debug"
    }
}

Bu yöntemi ekleyin:

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

1
Bu cevabı tercih ederim çünkü güvenilir. Yine de Google Haritalar API anahtarıma yeni bir "izin verilen Android uygulaması" girişi eklemem gerekiyordu (uygulama kimliği farklı olduğundan).
Baz

5

Sadece farklı bir anahtarla bir hata ayıklama yapısı da imzalanır. Eclipse tarafından otomatik olarak oluşturulur ve sertifikası yalnızca bir yıl geçerlidir. Sorun ne android:debuggable? Bu değeri kullanarak koddan alabilirsiniz PackageManager.


3

Bahsetmeye değer başka bir seçenek. Bazı kodları yalnızca hata ayıklayıcı eklendiğinde yürütmeniz gerekiyorsa, şu kodu kullanın:

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

0

İle çözüldü android:debuggable. Öğeyi okurken, bazı durumlarda öğedeki hata ayıklama bayrağının kayıtta saklanmadığı ve if (m.debug && !App.isDebuggable(getContext()))her zaman değerlendirildiği bir hataydı false. Benim hatam.


13
Bunun bir yıldan fazla olduğunun farkındayım, ancak @ Omar Rehman'ın cevabını kabul etmeliydin, bunu değil. Gönderdiğiniz şey, sonunda yaptığınız şey olsa da, sorduğunuz soruya gerçekten cevap vermiyor, öte yandan Omar'ın çözümü bunu yapıyor gibi görünüyor, yani kabul edilen övgüyü hak ediyor.
mah

7
@Mah - Birisine , problemini kendilerinin çözmesinden neredeyse bir yıl sonra gönderilen bir cevabı kabul etmemesi nedeniyle zorbalık yapmak son derece uygunsuz ! Ve bu, aday göstereceğiniz cevabın onların gittiğinden çok daha karmaşık olduğunu bile görmezden geliyor - bu, sorulan soruyu cevaplıyor, çünkü soru, bayrağın güvenilmez olduğuna dair yanlış bir izlenime yol açan bir hatadan kaynaklanıyordu. .
Chris Stratton

4
@ChrisStratton Cevabımın zorbalık olduğunu düşünüyorsanız, interneti çok okumadığınızı düşünüyorum. Sizin yaptığınız gibi, karşıt görüşünüzü bir yoruma gönderme hakkınızı destekliyorum ve sonuç olarak, yorumumu ve bu sorudaki diğer yazıları inceledim ve orijinal yorumumun arkasındayım: poster, meşru bir soru sordu ve birisi tarafından doğru şekilde cevaplandı. Kendi "cevabına" dayanarak, orijinal sorusu ilk başta sormak istediği şey değildir ... bir APK'nin imzası (sürüm veya hata ayıklama) manifestoyla tam olarak sıfır etkiye sahiptir.
mah

3
@mah - Soruyu soran kişiye bağlıdır, öne sürdüğünüz ayrımın önemli olup olmadığı da dahil olmak üzere gerçek uygulama ihtiyaçlarını neyin karşılayacağına karar vermek size değil - ya da görünüşe göre bu durumda değil. Daha da önemlisi, aday göstereceğiniz cevabın , gerçek ihtiyaçları karşılandıktan yaklaşık bir yıl sonra yayınlandığını tamamen görmezden geliyorsunuz . Bir yılın büyük bir bölümünde kabullerini değiştirmek için geri gelmediği için cezalandırmaktır ki bu da zorbalık teşkil eder.
Chris Stratton

3
@ChrisStratton, yanıt almak istediği asıl soruyu sormak da soruyu soran kişiye bağlıdır - bu durumda yapılmamış bir şey. Haklısınız, gönderilen cevabın aslında ne zaman verildiğini görmezden geldiğim için haklısınız, ancak hiçbir ceza yok, sadece makul bir fikrim var. Burada zorba gibi davrandığımı düşünüyorsanız, yorumumu kötüye kullanım olarak işaretlemenizi şiddetle rica ediyorum . Ancak bunu yapmadan önce, burada kendi ilanlarınızı incelemek isteyebilirsiniz.
mah

0

Kotlin'de şu anda kullandığım çözüm:

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

bu şekilde hata ayıklamada hala SIGN yapabilirim ve bunlar Crashlytics'e bildirilecek (örneğin, QA süreci için)

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.