据我所知,在Android中“发布版本”是签名的APK。如何从代码中检查它或Eclipse是否有某种秘密定义?
我需要它来调试从Web服务数据填充ListView项(不,logcat不是一个选项)。
我的想法:
- 应用程序的
android:debuggable
,但由于某种原因看起来不可靠。 - 硬编码设备ID不是一个好主意,因为我正在使用同一设备来测试签名的APK。
- 在代码中的某处使用手动标记?有道理,但肯定会忘记更改,而且所有程序员都懒惰。
据我所知,在Android中“发布版本”是签名的APK。如何从代码中检查它或Eclipse是否有某种秘密定义?
我需要它来调试从Web服务数据填充ListView项(不,logcat不是一个选项)。
我的想法:
android:debuggable
,但由于某种原因看起来不可靠。Answers:
有多种方法可以检查应用程序是否使用调试或发行证书来构建,但是以下方法对我来说似乎是最好的。
根据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;
}
java.security.cert.X509Certificate
,java.security.cert.CertificateException
和android.content.pm.Signature
。所有其他班级都没有为我呈现多次比赛
要检查可调试标志,可以使用以下代码:
boolean isDebuggable = ( 0 != ( getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE ) );
科特林:
val isDebuggable = 0 != applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE
有关更多信息,请参阅保护Android LVL应用程序安全。
另外,如果您正确使用Gradle,则可以检查BuildConfig.DEBUG
是对还是错。
马克·墨菲(Mark Murphy)回答
最简单,最好的长期解决方案是使用BuildConfig.DEBUG
。该boolean
值将true
用于调试版本,false
否则:
if (BuildConfig.DEBUG) {
// do something for a debug build
}
也许迟到了,但使用起来很混乱 BuildConfig.DEBUG
首先将其添加到您的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;
}
}
调试版本也用不同的密钥签名。它是由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(例如,用于质量检查流程)