在Android中,通过代码自动去除Log打印,常见的有两种主流方案:
方案一:ProGuard / R8 混淆去除(推荐)
在正式版构建时,通过混淆规则直接删除Log代码。
步骤:
- 在
proguard-rules.pro中添加规则:
# 移除所有Log调用
-assumenosideeffects class android.util.Log {
public static *** d(...);
public static *** v(...);
public static *** i(...);
public static *** w(...);
public static *** e(...);
public static *** wtf(...);
public static *** println(...);
}
# 如果只想保留某些级别(例如只保留e和wtf)
-assumenosideeffects class android.util.Log {
public static *** d(...);
public static *** v(...);
public static *** i(...);
public static *** w(...);
}
- 在
build.gradle中配置:
android {
buildTypes {
release {
minifyEnabled true // 启用混淆
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),
'proguard-rules.pro'
}
}
}
优点: 字节码级别删除,性能最好,Log代码完全不存在
缺点: 混淆后堆栈信息不准确(可保留行号)
方案二:BuildConfig 条件控制
通过BuildConfig字段在编译时控制Log调用。
步骤:
- 定义Log工具类:
public class Logger {
public static void d(String tag, String msg) {
if (BuildConfig.DEBUG) {
Log.d(tag, msg);
}
}
public static void i(String tag, String msg) {
if (BuildConfig.DEBUG) {
Log.i(tag, msg);
}
}
// ... 其他级别
}
- 使用自定义Log类:
Logger.d("TAG", "这条日志只在Debug模式下打印");
- build.gradle 配置(自动生成BuildConfig.DEBUG):
android {
buildTypes {
debug {
debuggable true
// BuildConfig.DEBUG = true
}
release {
debuggable false
// BuildConfig.DEBUG = false
}
}
}
优点: 简单易懂,不依赖混淆
缺点: Log代码仍在apk中,只是不执行
推荐组合方案
public class L {
public static void d(String tag, String msg) {
if (BuildConfig.DEBUG) {
Log.d(tag, msg);
}
}
}
// proguard-rules.pro 额外添加
-assumenosideeffects class com.yourpackage.L {
public static *** d(...);
}
这样Debug版本正常打印,Release版本连条件判断都会被优化掉。
注意事项
-
字符串拼接问题: 即使Log被移除,字符串拼接仍会执行
// 错误:字符串仍会拼接 Log.d(TAG, "user=" + user.toString()); // 正确:使用条件判断或延迟加载 if (BuildConfig.DEBUG) { Log.d(TAG, "user=" + user.toString()); } 保留异常堆栈: 建议保留
Log.e()用于记录异常-
Timber库: 推荐使用Timber,配合ProGuard规则更优雅
implementation 'com.jakewharton.timber:timber:5.0.1' // 在Application中 if (BuildConfig.DEBUG) { Timber.plant(new Timber.DebugTree()); }
最佳实践: 使用 ProGuard + BuildConfig 双重保证,开发阶段灵活控制,发布版本彻底移除。