【发布时间】:2012-05-05 11:06:26
【问题描述】:
从生产 android 应用程序中删除日志记录的最佳方法是什么。看来 proguard 并没有完全做到这一点,字符串仍然被写入,所以我想知道从生产代码中删除日志记录的最佳解决方案是什么?
【问题讨论】:
标签: android
从生产 android 应用程序中删除日志记录的最佳方法是什么。看来 proguard 并没有完全做到这一点,字符串仍然被写入,所以我想知道从生产代码中删除日志记录的最佳解决方案是什么?
【问题讨论】:
标签: android
IMO 最佳解决方案是在调用日志记录方法的任何位置编写如下代码。
if (SOME_LOG_CONSTANT) Log.d(TAG, "event:" + someSlowToEvaluateMethod());
通过更改 1 个常量,您可以删除所有不需要的日志记录。这样if (false) 后面的部分甚至不应该进入你的 .class 文件,因为编译器可以完全删除它(它是无法访问的代码)。
这也意味着如果您将整个代码块包装在 if 中,您可以从发布软件中排除整个代码块。这是连proguard都做不到的。
如果您使用 SDK Tools r17 及更高版本,SOME_LOG_CONSTANT 可以是 BuildConfig.DEBUG。该常量会根据构建类型自动为您更改。谢谢@Christopher
【讨论】:
if(??),那么表达式就不需要被计算了。
BuildConfig.DEBUG 的包装日志子句,使用 SDK Tools r17 及更高版本会自动为您执行此操作。这避免了必须为发布版本更改代码的笨拙。
if 是一个糟糕的选择?
使用 Timber,它是配置日志的好库: https://github.com/JakeWharton/timber
使用示例:Timber.d("Activity Created");
配置示例:
public class ExampleApp extends Application {
@Override public void onCreate() {
super.onCreate();
if (BuildConfig.DEBUG) {
Timber.plant(new DebugTree());
} else {
Timber.plant(new CrashReportingTree());
}
}
/** A tree which logs important information for crash reporting. */
private static class CrashReportingTree extends Timber.Tree {
@Override protected void log(int priority, String tag, String message, Throwable t) {
if (priority == Log.VERBOSE || priority == Log.DEBUG) {
return;
}
FakeCrashLibrary.log(priority, tag, message);
if (t != null) {
if (priority == Log.ERROR) {
FakeCrashLibrary.logError(t);
} else if (priority == Log.WARN) {
FakeCrashLibrary.logWarning(t);
}
}
}
}
【讨论】:
Configuring Your Application for Release 告诉您在发布应用程序之前只需删除 Log 命令。
您可以通过删除源文件中对 Log 方法的调用来停用日志记录。
我所做的是创建一个专有的静态日志方法,该方法读取类似这样的全局布尔值:
class MyLog {
private static final boolean LOGGING = true; //false to disable logging
public static void d(String tag, String message) {
if (LOGGING) {
Log.d(tag, message);
}
}
/* ... same for v, e, w, i */
}
在您想登录的任何地方使用它。
MyLog.d("Tag", "This will only work with LOGGING true");
【讨论】:
message 传递的所有内容都将在运行时进行评估,而不管LOGGING 的值如何。这对性能不利。
我建议你看看这个Log extension class。
它使您能够对日志进行精细控制。 例如,您可以禁用所有日志(感谢配置文件)或仅禁用某些包或类的日志。
此外,它还添加了一些有用的功能(例如,您不必为每个日志传递标签)。
【讨论】:
只需将此方法添加到您的代码中并使用 Logd 代替 Log.d
private static final String TAG = "your own tag to recognize log entries from this app";
public static void Logd(String txt) {
if (BuildConfig.DEBUG&&BuildConfig.BUILD_TYPE.equals("debug")) Log.d(TAG,txt);
}
我知道字符串仍将被评估,但我们在额外的处理时间中谈论微秒。除非您循环执行数千次日志记录,否则没人会注意到应用速度的差异。
DEBUG 和 BUILD_TYPE 可在 Android Studio 中使用。 DEBUG 布尔值是 build.gradle 文件中的“可调试”选项:
buildTypes {
debug {
debuggable true
runProguard false
proguardFile getDefaultProguardFile('proguard-android.txt')
}
release {
debuggable false
runProguard true
proguardFile getDefaultProguardFile('proguard-android.txt')
}
}
当您在 Android Studio 中运行时,BUILD_TYPE 会自动设置为“调试”。
因此,如果您将 debuggable 设置为 false 或用户拥有发布版本,则日志将消失。
【讨论】:
我建议你看看 Roboguice - http://code.google.com/p/roboguice/ - 如果你使用内置的 Ln 功能,它会自动不登录已签名的 APK。它还简化了大量其他 Android 样板。您可以使用 Basedroid 看到它的实际效果 - https://github.com/achuinard/basedroid
【讨论】:
【讨论】:
根据我的经验,最好的方法是处理这个问题,
首先在记录时检查 BuildConfig.DEBUG 标志以打印日志。
Class LogUtils{
public static void log(Class clazz, String message) {
if (BuildConfig.DEBUG) {//log only in debug mode
Log.d(clazz.getSimpleName(), message);
}
}
}
然后启用 minify 到您的应用程序模块 gradle 文件,这将使 proguard 能够优化您的二进制文件
android {
buildTypes {
release {
minifyEnabled true
//shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}
}
}
这将在您的调试版本中保留调试日志。
但是在您的发布版本中,if (BuildConfig.DEBUG) 条件永远不会为真,因此 proguard 将从您的二进制文件中删除无法访问的日志代码。
【讨论】: