Android 从代码中检测应用程序是否为生产/发布版本
我的应用程序中有一个自制的日志系统。它所做的事情之一是在开发过程中执行大量日志记录(到文件和logcat),并且可以通过一个可变的更改完全关闭。有关功能示例:Android 从代码中检测应用程序是否为生产/发布版本,android,Android,我的应用程序中有一个自制的日志系统。它所做的事情之一是在开发过程中执行大量日志记录(到文件和logcat),并且可以通过一个可变的更改完全关闭。有关功能示例: static public final boolean DEVELOPMENT_VERBOSE = true; public static void developmentLogMessage(String message) { if (DEVELOPMENT_VERBOSE) Log.i("com.xxx.a
static public final boolean DEVELOPMENT_VERBOSE = true;
public static void developmentLogMessage(String message) {
if (DEVELOPMENT_VERBOSE)
Log.i("com.xxx.app", message);
}
我遇到的问题(可能更麻烦的是)是,我必须记住为发布设置DEVELOPMENT\u VERBOSE=false
。代码中是否有一种方法可以检测应用程序何时最终发布(例如检查签名的apk),以便我可以通过编程方式将DEVELOPMENT\u VERBOSE
设置为false
我看了一下,但似乎我的应用程序在为市场签名之前就已经有了签名
try {
PackageManager manager = context.getPackageManager();
PackageInfo appInfo = manager.getPackageInfo(
"com.xxx.app", PackageManager.GET_SIGNATURES
);
System.out.println(appInfo.signatures[0].toCharsString());
} catch (NameNotFoundException e) {
}
我希望签名数组是空的,我可以找到其中的一个。但是不行。你可以查看哪个证书被用来签署应用程序,并据此采取行动 例如:
for (Signature sig : getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_SIGNATURES).signatures) {
// Get some (pseudo)uniqe value:
long sigHash = Arrays.hashCode(sig.toByteArray());
if (sigHash == releaseSigHash) DEVELOPMENT_VERBOSE = false;
}
下面是我为GoogleMapView所做的,决定使用哪个API键,这是一个类似的问题
for (Signature sig : getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_SIGNATURES).signatures) {
MessageDigest m = MessageDigest.getInstance("MD5");
m.update(sig.toByteArray());
md5 = new BigInteger(1, m.digest()).toString(16);
Log.d("findApiNøgle", "md5fingerprint: "+md5);
// Jacobs debug-nøgle
if (md5.equals("5fb3a9c4a1ebb853254fa1aebc37a89b")) return "0osb1BfVdrk1u8XJFAcAD0tA5hvcMFVbzInEgNQ";
// Jacobs officielle nøgle
if (md5.equals("d9a7385fd19107698149b7576fcb8b29")) return "0osb1BfVdrk3etct3WjSX-gUUayztcGvB51EMwg";
// indsæt din egen nøgle her:
}
您可以使用在生成发布时完全关闭相应的日志。ProGuard可以做很多有趣的事情。除此之外,它还可以在构建过程中缩减不需要的代码。例如,如果在开发过程中使用调试日志(log.d()),但希望在发行版中禁用它,则可以将以下行添加到proguard.cfg中:
-assumenosideeffects class android.util.Log {
public static int d(...);
}
要启用ProGuard,请设置属性
proguard.config=proguard.cfg
到您的
项目.properties
(如果使用默认位置)。请注意,ProGuard在默认情况下还将执行其他一些操作,因此在发布项目时,您可能应该采取一些额外的步骤。至少您确实希望保存生成的mapping.txt
文件。有关更多详细信息,请参阅。经过一些研究/工作后,我们可以找到一个解决方案来检查签名证书
static public boolean DEVELOPMENT_VERBOSE = false;
static private final X500Principal RELEASE_DN = new X500Principal(
"CN=aaa,OU=bbb,O=ccc,L=ddd,ST=eee,C=fff"
);
// auto disable the development logs if the apk is signed with a cert
try {
PackageManager manager = context.getPackageManager();
PackageInfo appInfo = manager.getPackageInfo("com.xxx.app",
PackageManager.GET_SIGNATURES);
Signature raw = appInfo.signatures[0];
try {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(raw.toByteArray()));
//DEVELOPMENT_VERBOSE = cert.getSubjectX500Principal().equals(DEBUG_DN);
if (!cert.getSubjectX500Principal().equals(RELEASE_DN))
DEVELOPMENT_VERBOSE = true;
} catch (CertificateException e) {
}
} catch (NameNotFoundException e) {
}
只要您在不同版本的应用程序中使用相同的证书,这将始终有效。一个问题,本例中的releaseSigHash是否会因已签名的应用程序的每个版本而更改?或者你可以反复使用相同的签名(我的第一个应用:))这对使用第三方模块很有效,但我看不出一个应用如何在自身上使用它。如何生成和验证md5是个鸡毛蒜皮的问题。@sanders:No releaseSigash永远不会更改,除非您创建另一个开发人员密钥。这就是重点!运行代码,打印生成的sigHash,并将值放入名为releasesigash的变量中。我不知道怎样才能澄清,让你明白我的意思。也许你只是试试看?是的,当你使用另一个完成的模块,如谷歌地图视图时,效果很好,但试着在你自己的应用程序上从你自己的应用程序中执行此操作。尝试生成/打印md5的行为将改变md5的最终值。这可以实现简单的日志排除,但我不确定是否要删除大量代码。例如,生成要记录的大型/复杂字符串的代码。此技术用于禁用在任何类中调用任何方法的效果,除非此类方法返回某个地方使用的值。在上面的示例中,它是一个
android.util.Log.d()
方法。使用这种方法,ProGuard将删除对此方法的任何调用,就像从未调用过一样。那么,您对“生成要记录的大型/复杂字符串的代码”的想法是什么呢?实际上,您的操作与我在下面的回答完全相同,但方式非常复杂。无需生成X509证书或将开发人员证书中的数据添加到代码中。就用散列。