Nic*_*oul 381 logging android proguard android-log
据谷歌称,在发布我的Android应用程序之前,我必须" 停用源代码中对Log方法的任何调用 ".摘录自出版物清单的第5部分:
在构建应用程序以进行发布之前,请确保停用日志记录并禁用调试选项.您可以通过删除源文件中对Log方法的调用来停用日志记录.
我的开源项目很大,每次发布时手动执行都很痛苦.此外,删除日志行可能很棘手,例如:
if(condition)
Log.d(LOG_TAG, "Something");
data.load();
data.show();
Run Code Online (Sandbox Code Playgroud)
如果我对日志行进行注释,则条件适用于下一行,并且可能不会调用load().这种情况是否足够罕见,我可以决定它不应该存在?
这是在官方清单上,所以我想很多人会定期这样做.
那么,如何有效但安全地删除所有日志行?
Chr*_*Orr 479
我发现一个更容易的解决方案是忘记所有if
地方的所有检查,并在我们调用Ant 目标时使用ProGuard去除任何Log.d()
或Log.v()
方法调用release
.
这样,我们总是为常规构建输出调试信息,而不必为发布版本进行任何代码更改.ProGuard还可以对字节码执行多次传递,以删除其他不需要的语句,空块,并可以在适当的情况下自动内联短方法.
例如,这是一个非常基本的Android ProGuard配置:
-dontskipnonpubliclibraryclasses
-dontobfuscate
-forceprocessing
-optimizationpasses 5
-keep class * extends android.app.Activity
-assumenosideeffects class android.util.Log {
public static *** d(...);
public static *** v(...);
}
Run Code Online (Sandbox Code Playgroud)
因此,您可以将其保存到文件中,然后从Ant调用ProGuard,传入刚刚编译的JAR和您正在使用的Android平台JAR.
另请参阅ProGuard手册中的示例.
更新(4.5年后):现在我使用Timber进行Android日志记录.
它不仅比默认Log
实现更好- 日志标记是自动设置的,并且很容易记录格式化的字符串和异常 - 但您也可以在运行时指定不同的日志记录行为.
在此示例中,日志记录语句将仅在我的应用程序的调试版本中写入logcat:
木材在我的Application
onCreate()
方法中设置:
if (BuildConfig.DEBUG) {
Timber.plant(new Timber.DebugTree());
}
Run Code Online (Sandbox Code Playgroud)
然后我的代码中的任何其他地方都可以轻松记录:
Timber.d("Downloading URL: %s", url);
try {
// ...
} catch (IOException ioe) {
Timber.e(ioe, "Bad things happened!");
}
Run Code Online (Sandbox Code Playgroud)
有关更高级的示例,请参阅Timber示例应用程序,其中所有日志语句在开发期间发送到logcat,在生产中,不会记录任何调试语句,但会向Crashlytics静默报告错误.
小智 114
所有好的答案,但是当我完成了我的开发时,我不想在所有Log调用中使用if语句,也不想使用外部工具.
所以我使用的解决方案是用我自己的Log类替换android.util.Log类:
public class Log {
static final boolean LOG = BuildConfig.DEBUG;
public static void i(String tag, String string) {
if (LOG) android.util.Log.i(tag, string);
}
public static void e(String tag, String string) {
if (LOG) android.util.Log.e(tag, string);
}
public static void d(String tag, String string) {
if (LOG) android.util.Log.d(tag, string);
}
public static void v(String tag, String string) {
if (LOG) android.util.Log.v(tag, string);
}
public static void w(String tag, String string) {
if (LOG) android.util.Log.w(tag, string);
}
}
Run Code Online (Sandbox Code Playgroud)
我在所有源文件中唯一要做的就是用我自己的类替换android.util.Log的导入.
hac*_*bod 60
我建议在某处使用静态布尔值来指示是否记录:
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;
Run Code Online (Sandbox Code Playgroud)
使用相应的代码:
if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT) Log.v(
TAG, "Adding window " + window + " at "
+ (i+1) + " of " + mWindows.size() + " (after " + pos + ")");
Run Code Online (Sandbox Code Playgroud)
Nic*_*oul 30
Christopher的Proguard解决方案是最好的,但如果出于任何原因你不喜欢Proguard,这是一个非常低技术的解决方案:
评论日志:
find . -name "*\.java" | xargs grep -l 'Log\.' | xargs sed -i 's/Log\./;\/\/ Log\./g'
Run Code Online (Sandbox Code Playgroud)
取消注释日志:
find . -name "*\.java" | xargs grep -l 'Log\.' | xargs sed -i 's/;\/\/ Log\./Log\./g'
Run Code Online (Sandbox Code Playgroud)
约束是您的日志记录指令不得跨越多行.
(在项目根目录的UNIX shell中执行这些行.如果使用Windows,获取UNIX层或使用等效的Windows命令)
Vin*_*ren 16
我想添加一些关于在Android Studio和gradle中使用Proguard的精度,因为我从最终的二进制文件中删除了日志行有很多问题.
为了使assumenosideeffects
Proguard作品,有一个先决条件.
在gradle文件中,您必须指定proguard-android-optimize.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'
}
}
Run Code Online (Sandbox Code Playgroud)
实际上,在默认proguard-android.txt
文件中,使用两个标志禁用优化:
-dontoptimize
-dontpreverify
Run Code Online (Sandbox Code Playgroud)
该proguard-android-optimize.txt
文件不会添加这些行,所以现在assumenosideeffects
可以工作.
然后,个人,我使用SLF4J,当我开发一些分发给其他人的库时,更是如此.优点是默认情况下没有输出.如果集成商想要一些日志输出,他可以使用Logback for Android并激活日志,因此可以将日志重定向到文件或LogCat.
如果我真的需要从最终库中删除日志,那么我会添加到我的Proguard文件中(proguard-android-optimize.txt
当然启用了文件后):
-assumenosideeffects class * implements org.slf4j.Logger {
public *** trace(...);
public *** debug(...);
public *** info(...);
public *** warn(...);
public *** error(...);
}
Run Code Online (Sandbox Code Playgroud)
我强烈建议使用杰克沃顿的木材
https://github.com/JakeWharton/timber
它解决了启用/禁用问题以及自动添加标记类的问题
只是
public class MyApp extends Application {
public void onCreate() {
super.onCreate();
//Timber
if (BuildConfig.DEBUG) {
Timber.plant(new DebugTree());
}
...
Run Code Online (Sandbox Code Playgroud)
日志只会在您的调试版中使用,然后使用
Timber.d("lol");
Run Code Online (Sandbox Code Playgroud)
要么
Timber.i("lol says %s","lol");
Run Code Online (Sandbox Code Playgroud)
打印
"你的课程/ msg"没有指定标签
我使用了像Google IO示例应用程序中的LogUtils类.我将其修改为使用特定于应用程序的DEBUG常量而不是BuildConfig.DEBUG,因为BuildConfig.DEBUG不可靠.然后在我的课程中我有以下内容.
import static my.app.util.LogUtils.makeLogTag;
import static my.app.util.LogUtils.LOGV;
public class MyActivity extends FragmentActivity {
private static final String TAG = makeLogTag(MyActivity.class);
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LOGV(TAG, "my message");
}
}
Run Code Online (Sandbox Code Playgroud)
我发布的此解决方案专门适用于Android Studio用户.我最近还发现了Timber并通过以下方式将其成功导入我的应用程序:
将最新版本的库放入build.gradle:
compile 'com.jakewharton.timber:timber:4.1.1'
Run Code Online (Sandbox Code Playgroud)
然后在Android工作室中,转到编辑 - >查找 - >替换路径...
输入Log.e(TAG,
或者您已将日志消息定义到"Text to find"
文本框中.然后你只需用它替换它Timber.e(
单击查找,然后单击全部替换.
Android工作室现在将浏览项目中的所有文件,并将所有日志替换为Timbers.
我使用这种方法的唯一问题是gradle后来出现了大量的错误消息,因为它无法在每个java文件的导入中找到"Timber".只需点击错误,Android Studios就会自动将"Timber"导入您的java.为所有错误文件完成后,gradle将再次编译.
您还需要将这段代码放在您onCreate
的Application
类的方法中:
if (BuildConfig.DEBUG) {
Timber.plant(new Timber.DebugTree());
}
Run Code Online (Sandbox Code Playgroud)
这将导致应用程序仅在您处于开发模式而非生产模式时进行日志记录.您还可以BuildConfig.RELEASE
登录发布模式.
每个android.util.Log提供了一种启用/禁用日志的方法:
public static native boolean isLoggable(String tag, int level);
Run Code Online (Sandbox Code Playgroud)
默认方法isLoggable(...)返回false,只有在设备中的setprop之后才会这样:
adb shell setprop log.tag.MyAppTag DEBUG
Run Code Online (Sandbox Code Playgroud)
这意味着可以打印任何DEBUG级别以上的日志.参考android doc:
检查指定标记的日志是否可以在指定级别进行记录.任何标记的默认级别都设置为INFO.这意味着将记录任何级别以上且包括INFO.在对日志记录方法进行任何调用之前,应检查是否应记录您的标记.您可以通过设置系统属性来更改默认级别:'setprop log.tag.'级别是VERBOSE,DEBUG,INFO,WARN,ERROR,ASSERT或SUPPRESS.SUPPRESS将关闭标签的所有日志记录.您还可以创建一个local.prop文件,其中包含以下内容:'log.tag.='并将其放在/data/local.prop中.
所以我们可以使用自定义日志工具:
public final class Dlog
{
public static void v(String tag, String msg)
{
if (Log.isLoggable(tag, Log.VERBOSE))
Log.v(tag, msg);
}
public static void d(String tag, String msg)
{
if (Log.isLoggable(tag, Log.DEBUG))
Log.d(tag, msg);
}
public static void i(String tag, String msg)
{
if (Log.isLoggable(tag, Log.INFO))
Log.i(tag, msg);
}
public static void w(String tag, String msg)
{
if (Log.isLoggable(tag, Log.WARN))
Log.w(tag, msg);
}
public static void e(String tag, String msg)
{
if (Log.isLoggable(tag, Log.ERROR))
Log.e(tag, msg);
}
}
Run Code Online (Sandbox Code Playgroud)
在 proguard-rules.pro 中输入以下代码`
-assumenosideeffects class android.util.Log {
public static *** d(...);
public static *** v(...);
public static *** w(...);
public static *** i(...);
public static *** e(...);
}
Run Code Online (Sandbox Code Playgroud)
# 如果您希望日志中包含调试类型错误,您可以删除特定的调试类
在build.gradle(app) ->android
做这件事
buildTypes {
debug{
debuggable false
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-
optimize.txt'), 'proguard-rules.pro'
}
release {
debuggable false
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-
optimize.txt'), 'proguard-rules.pro'
}
}
lintOptions {
checkReleaseBuilds false
// Or, if you prefer, you can continue to check for errors in release builds,
// but continue the build even when errors are found:
abortOnError false
}
Run Code Online (Sandbox Code Playgroud)
如果您可以运行一次全局替换,然后保留一些编码约定,则可以遵循Android 框架中经常使用的模式。
而不是写作
Log.d(TAG, string1 + string2 + arg3.toString());
Run Code Online (Sandbox Code Playgroud)
有它
if (BuildConfig.DEBUG) Log.d(TAG, string1 + String.format("%.2f", arg2) + arg3.toString());
Run Code Online (Sandbox Code Playgroud)
现在,proguard可以从优化的发行版DEX中删除StringBuilder及其使用的所有字符串和方法。使用proguard-android-optimize.txt
,您无需担心android.util.Log登录您的proguard-rules.pro
:
android {
…
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
Run Code Online (Sandbox Code Playgroud)
有了Android Studio gradle插件,它是相当可靠的,因此您不需要额外的常量来控制剥离。BuildConfig.DEBUG
归档时间: |
|
查看次数: |
157089 次 |
最近记录: |