Android 从代码中检测应用程序是否为生产/发布版本

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

我的应用程序中有一个自制的日志系统。它所做的事情之一是在开发过程中执行大量日志记录(到文件和logcat),并且可以通过一个可变的更改完全关闭。有关功能示例:

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证书或将开发人员证书中的数据添加到代码中。就用散列。