9

在 C++ 中,我通常会设置 2 个构建 - 分别具有DEBUGRELEASE预定义的调试和发布。然后,我将使用这些定义来确定常量值,例如启用/禁用日志记录、服务器 URL 等。

现在,在 Java/Android 中,我在构建发布之前注释掉了一些东西。这不是一个好方法,我可以说。我可能会忘记一些事情。

在构建发布版本(已签名)或调试版本(未签名)时,确保不会忘记任何内容的常见做法是什么?

4

5 回答 5

18

如果您从 Eclipse 运行应用程序,它将始终是一个调试程序。

当您导出应用程序时(Android 工具 -> 导出(未)签名的应用程序包)

如果你想动态知道它是发布还是调试,你可以使用 BuildConfig.DEBUG (它位于 gen 文件夹中,我不知道是否所有 API 级别都支持)

如下所示:

if (BuildConfig.DEBUG) {
    Log.d(TAG, "Text");
}

如果您查看生成的字节码,您将看到以下内容(在调试模式下):

public class Sample{

    private static final boolean LOG_ENABLED = true;

    public static void main(String args[]){
        if (BuildConfig.DEBUG){
            System.out.println("Hello World");
        }
    }
}

产生以下字节码:

public class Sample extends java.lang.Object{
    public Sample();
      Code:
       0:   aload_0
       1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
       4:   return

    public static void main(java.lang.String[]);
      Code:
       0:   getstatic   #2; //Field java/lang/System.out:Ljava/io/PrintStream;
       3:   ldc #3; //String Hello World
       5:   invokevirtual   #4; //Method Java/io/PrintStream.println(Ljava/lang/String;)V
       8:   return

}

如果 BuildConfig.DEBUG 为假

public class Sample extends java.lang.Object{
    public Sample();
      Code:
       0:   aload_0
       1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
       4:   return

    public static void main(java.lang.String[]);
      Code:
       0:   return
}
于 2012-09-17T12:12:19.310 回答
8

Java 没有(默认情况下)任何预处理器,因此#ifdef在编译时没有任何东西。但是,如果您不介意将调试代码留在应用程序中,则可以使用以下代码检查应用程序是否在运行时发布或调试:

Boolean release = (getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE);

检查debuggable标志值。并且所说的 flad 自动设置为false用于发布版本和true调试版本。

如果你想摆脱一些调试代码,你可以尝试使用 ProGuard 去除某些类或方法。默认情况下,ProGuard 仅参与发布构建的构建过程。

于 2012-09-17T12:17:18.603 回答
0

我通常创建一个单独的日志类,在其中设置一个静态 DEBUG 变量。现在,在获得生产版本之前,我需要做的就是将该 DEBUG 变量设置为 false。

public class Log {
     public final static String LOGTAG = "APP NAME";

      public static final boolean DEBUG = true;

      public static void v(String msg) {
        android.util.Log.v(LOGTAG, msg);
      }

      public static void e(String msg) {
        android.util.Log.e(LOGTAG, msg);
      }

      public static void d(String msg) {
          android.util.Log.d(LOGTAG, msg);
      }
}

对于日志记录 -

if(Log.DEBUG) Log.v("In some function x. Doing y.");
于 2012-09-17T12:14:15.127 回答
0

每次我将项目作为 android 应用程序运行时,我都面临同样的问题,它曾经在调试器模式下打开,但后来问题解决了。

- 如果您在 Eclipse 中工作,则必须使用 Java EE 透视图 - 而只是选择 Java 透视图。

- 清理你的应用程序。- 从设备上卸载应用程序。- 重新启动您的设备(就像这样,以便不存储缓存) - 运行您的应用程序。

这次不会显示调试器模式。复制 bin 文件夹中生成的 apk 并在其他设备上试用

于 2013-10-05T10:47:51.033 回答
0

我找到了一种体面地模拟预处理指令的方法:

在我的 Gradle 中buildTypes,我定义:

release {
    buildConfigField "boolean", "isDebug", "false"
    ...
}

debug {
    buildConfigField "boolean", "isDebug", "true"
    ...
}

然后,在我的代码中,我执行以下操作:

if (BuildConfig.isDebug) {
    ... do debug stuff ...
}

如果需要,当然:

else {
    ... do release stuff ...
}

这两个块都存在于debugAPK 中,但是在构建release版本时,Proguard 足够聪明地确定debug可以删除该块,因为它依赖于 a if (false)(它也从生成的代码中删除)。

如果您从块中调用一些特定于调试的类debug并且仅从那里调用,它们将从生成的 APK 中删除,因为它们被认为是未使用的,这也是一个有趣的点:您的代码不能以它会使用的方式进行调整代码。

我可以通过检查我的dump,mappingusageProguard 输出文件来确定所有这些。

于 2016-03-04T11:25:25.413 回答