根据谷歌,我必须在发布我的Android应用程序谷歌播放之前“停用源代码中的Log方法的任何调用”。出版清单第3节节选:

在构建应用程序发布之前,请确保禁用了日志记录并禁用了调试选项。您可以通过删除源文件中对Log方法的调用来禁用日志记录。

我的开源项目很大,每次发布都要手动完成,这很痛苦。此外,删除Log行可能很棘手,例如:

if(condition)
  Log.d(LOG_TAG, "Something");
data.load();
data.show();

如果注释Log行,则该条件将应用于下一行,并且可能不会调用load()。这样的情况是否罕见到我可以决定它不应该存在?

那么,是否有更好的源代码级方法来做到这一点呢?或者是一些聪明的ProGuard语法,有效但安全地删除所有Log行?


当前回答

ProGuard将在你的发布版本中为你做这件事,现在来自android.com的好消息是:

http://developer.android.com/tools/help/proguard.html

ProGuard工具通过删除未使用的代码和用语义模糊的名称重命名类、字段和方法来缩小、优化和混淆代码。结果是一个更小的.apk文件,更难以进行反向工程。由于ProGuard使应用程序更难进行反向工程,因此当应用程序使用对安全性敏感的特性时,例如在应用程序授权时,使用它是很重要的。

ProGuard集成到Android构建系统中,所以你不需要手动调用它。ProGuard仅在以发布模式构建应用程序时运行,因此在以调试模式构建应用程序时不必处理混淆的代码。运行ProGuard是完全可选的,但强烈推荐。

本文档介绍如何启用和配置ProGuard,以及如何使用retrace工具解码混淆的堆栈跟踪

其他回答

克里斯托弗的Proguard解决方案是最好的,但如果因为任何原因你不喜欢Proguard,这里有一个非常低技术含量的解决方案:

评论日志:

find . -name "*\.java" | xargs grep -l 'Log\.' | xargs sed -i 's/Log\./;\/\/ Log\./g'

取消日志:

find . -name "*\.java" | xargs grep -l 'Log\.' | xargs sed -i 's/;\/\/ Log\./Log\./g'

一个限制是您的日志记录指令不能跨越多行。

(在项目根的UNIX shell中执行这些行。如果使用Windows,请使用UNIX层或使用等效的Windows命令)

我建议在某个地方使用一个静态布尔值来指示是否记录日志:

class MyDebug {
  static final boolean LOG = true;
}

然后无论你想在哪里登录你的代码,只需要这样做:

if (MyDebug.LOG) {
  if (condition) Log.i(...);
}

现在,当你将MyDebug.LOG设置为false时,编译器将剔除这些检查中的所有代码(因为它是一个静态final,它在编译时知道代码没有被使用)。

对于较大的项目,您可能希望开始在单个文件中使用布尔值,以便能够根据需要轻松启用或禁用日志记录。例如,这些是我们在窗口管理器中拥有的各种日志常量:

static final String TAG = "WindowManager";
static final boolean DEBUG = false;
static final boolean DEBUG_FOCUS = false;
static final boolean DEBUG_ANIM = false;
static final boolean DEBUG_LAYOUT = false;
static final boolean DEBUG_RESIZE = false;
static final boolean DEBUG_LAYERS = false;
static final boolean DEBUG_INPUT = false;
static final boolean DEBUG_INPUT_METHOD = false;
static final boolean DEBUG_VISIBILITY = false;
static final boolean DEBUG_WINDOW_MOVEMENT = false;
static final boolean DEBUG_ORIENTATION = false;
static final boolean DEBUG_APP_TRANSITIONS = false;
static final boolean DEBUG_STARTING_WINDOW = false;
static final boolean DEBUG_REORDER = false;
static final boolean DEBUG_WALLPAPER = false;
static final boolean SHOW_TRANSACTIONS = false;
static final boolean HIDE_STACK_CRAWLS = true;
static final boolean MEASURE_LATENCY = false;

对应代码如下:

    if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT) Log.v(
        TAG, "Adding window " + window + " at "
        + (i+1) + " of " + mWindows.size() + " (after " + pos + ")");

我想添加一些关于使用Proguard与Android Studio和gradle的精度,因为我有很多问题,从最终的二进制文件中删除日志行。

为了使保护工作中的副作用假设,有一个先决条件。

在你的gradle文件中,你必须指定proguard-android- optimization .txt作为默认文件。

buildTypes {
    release {
        minifyEnabled true
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'

        // With the file below, it does not work!
        //proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
}

实际上,在默认的proguard-android.txt文件中,通过以下两个标志禁用了优化:

-dontoptimize
-dontpreverify

proguard-android- optimization .txt文件没有添加这些行,所以现在假设副作用可以工作。

然后,就我个人而言,我使用SLF4J,特别是当我开发一些分发给其他人的库时。其优点是默认情况下没有输出。如果积分器想要一些日志输出,他可以使用Android的Logback并激活日志,这样日志就可以重定向到文件或LogCat。

如果我真的需要从最终库中剥离日志,我就会添加到我的Proguard文件中(当然是在启用了Proguard -android- optimization .txt文件之后):

-assumenosideeffects class * implements org.slf4j.Logger {
    public *** trace(...);
    public *** debug(...);
    public *** info(...);
    public *** warn(...);
    public *** error(...);
}

这就是我过去在我的android项目上所做的。

在Android Studio我们可以做类似的操作,Ctrl+Shift+F从整个项目(命令+Shift+F在MacOs)和Ctrl+Shift+R替换((命令+Shift+R在MacOs))

我有一个很简单的解决办法。我使用IntelliJ进行开发,因此细节有所不同,但这个想法应该适用于所有IDE。

我选择我的源树的根,右键单击并选择“替换”。然后我选择将所有“Log.”替换为“//Log.”。这将删除所有日志语句。为了稍后将它们放回去,我重复相同的替换,但这次将所有“//Log.”替换为“Log.”。

对我来说太好了。只需记住将replace设置为区分大小写,以避免出现“Dialog.”之类的意外。为了获得额外的保证,您还可以使用“Log.”作为要搜索的字符串执行第一步。

辉煌。