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

据我所知,在安卓系统中“发布版本”是签名 APK。如何检查它 来自代码或 Eclipse 是否有某种秘密定义?

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

我的想法是:

  • 应用程序是 android:debuggable,但由于某些原因,它看起来不可靠。
  • 硬编码设备 ID 不是一个好主意,因为我使用相同的设备来测试签名的 APK。
  • 在代码中使用手动标志?貌似有道理,但总有一天会忘记改变再加上所有程序员都很懒。
83603 次浏览

调试版本也是签名的,只是使用了不同的键。它是由 Eclipse 自动生成的,其证书仅有效一年。android:debuggable有什么问题?可以使用 PackageManager从代码中获取此值。

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

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

科特林:

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

有关详细信息,请参阅 保护 Android LVL 应用程序的安全

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

android:debuggable解决。在读取条目时出现错误,在某些情况下,条目上的调试标志没有存储在记录中,因此 if (m.debug && !App.isDebuggable(getContext()))总是计算为 false。我的错。

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

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

也许晚了,但是 iosching 使用 BuildConfig.DEBUG

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

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

如果 APK不可调试,则输出 0; 如果可调试,则输出 1

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

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

马克 · 墨菲回答

最简单、也是最好的长期解决方案 是使用 BuildConfig.DEBUG。这是一个 boolean值,对于一个调试构建,它将是 true,否则是 false:

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

首先将它添加到 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;
}
}

我目前在 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 过程)