我需要这个来调试从Web服务数据填充ListView项目(不,logcat不是一个选项)。
我的想法:
- 应用程序的android:debuggable属性,但由于某些原因,这似乎不太可靠。 - 硬编码设备ID不是个好主意,因为我正在使用同一台设备测试已签名的APK。 - 在代码中使用手动标记?这是可行的,但我肯定会在某个时候忘记更改,而且所有程序员都很懒。
您可以使用以下代码来检查debuggable标志:
boolean isDebuggable = ( 0 != ( getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE ) );
Kotlin:
=>Kotlin:
val isDebuggable = 0 != applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE
了解更多信息,请参阅Securing Android LVL Applications。
或者,如果您正确使用Gradle,则可以检查BuildConfig.DEBUG
是否为真或假。
由Mark Murphy回答
最简单且长期最佳的解决方案是使用BuildConfig.DEBUG
。这是一个布尔值,对于调试版本将为true
,否则将为false
:
if (BuildConfig.DEBUG) {
// do something for a debug build
}
有多种方法可以检查应用程序是使用调试还是发布证书构建的,但以下方式对我来说似乎是最好的。
根据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;
}
如果您想静态地检查一个 APK
,您可以使用
aapt dump badging /path/to/apk | grep -c application-debuggable
如果 APK
未调试,则输出 0
,如果已经调试,则输出 1
。
/Users/USER_NAME/library/Android/sdk/build-tools/28.0.3/aapt
。 - Casey也许有点晚了,但是iosched使用了BuildConfig.DEBUG
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过程)