如何检查APK是否已签名或“调试版本”?

时间:2011-08-16 22:07:02

标签: android debugging certificate

据我所知,在android“发布版”中签名为APK。如何检查从代码或Eclipse是否有一些秘密定义?

我需要这个来调试从Web服务数据中填充ListView项目(不,logcat不是一个选项)。

我的想法:

  • 应用程序的android:debuggable,但由于某种原因看起来不可靠。
  • 硬编码设备ID不是一个好主意,因为我使用相同的设备来测试签名的APK。
  • 在代码中的某处使用手动标记?看似合理,但肯定会在某个时候忘记改变,加上所有程序员都很懒惰。

10 个答案:

答案 0 :(得分:135)

要检查可调试标志,可以使用以下代码:

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

科特林:

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

有关详细信息,请参阅Securing Android LVL Applications

或者,如果您正确使用Gradle,则可以检查BuildConfig.DEBUG是真还是假。

答案 1 :(得分:130)

Mark Murphy回答

最简单,最好的长期解决方案,就是使用BuildConfig.DEBUG。对于调试版本,这是booleantrue,否则为false

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

答案 2 :(得分:76)

有不同的方法来检查应用程序是否使用调试版或发布证书构建,但以下方式对我来说似乎最好。

根据Android文档Signing Your Application中的信息,调试密钥包含以下主题专有名称:“ 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;
}

答案 3 :(得分:21)

也许迟到了,但iosched使用BuildConfig.DEBUG

答案 4 :(得分:18)

如果要静态检查APK,可以使用

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

如果0不可调试,则输出APK,如果是1,则输出{。}}。

答案 5 :(得分: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;
    }
}

答案 6 :(得分:5)

也会使用不同的密钥对调试版本进行签名。它由Eclipse自动生成,其证书有效期仅为一年。 android:debuggable有什么问题?您可以使用PackageManager从代码中获取此值。

答案 7 :(得分:3)

另一种选择,值得一提。如果只在附加调试器时需要执行某些代码,请使用以下代码:

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

答案 8 :(得分:0)

解决android:debuggable。读取项目时出现错误,在某些情况下,项目上的调试标记未存储在记录中,if (m.debug && !App.isDebuggable(getContext()))始终评估为false。我的坏。

答案 9 :(得分:0)

我目前正在使用的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(例如,用于质量检查流程)