如何消除所有调试记录电话之前建筑物的发行版本的应用程序?
-
20-09-2019 - |
题
根据谷歌,我必须"关闭任何电话日志方法的源代码"以前发布我的机器程序。提取从第3节 出版物清单:
确保你停用的记录和禁用的调试的选项之前建立你的申请释放。你可以停用的记录通过删除的电话日志中的方法来源的文件。
我开源项目就是大的,它是一个痛苦做手工每次我释放。此外,除一个日志线路可能是棘手的,例如:
if(condition)
Log.d(LOG_TAG, "Something");
data.load();
data.show();
如果我评论的日志中线,然后在条件适用于下一个线和机会是负载()不叫。是这样的情况罕见,我可以决定它不应该存在吗?
那么,是否有更好的源代码水平的方式做到这一点吗?或者也许某些聪明的ProGuard语法,以高效而安全地删除所有的日志线路?
解决方案
我找到一个容易的解决办法是忘记所有的 if
检查所有的地方只使用 ProGuard 到条出任何 Log.d()
或 Log.v()
方法的呼吁时,我们呼吁我们的蚂蚁 release
目标。
这样,我们总是有"调试"的信息被输出为定期的基础,并没有作出任何代码变化对于释放生成。ProGuard还可以做多穿过码除其他不希望发言,空块和可以自动内联短的方法在适当情况下。
例如,这是一个非常基本的ProGuard配置问题:
-dontskipnonpubliclibraryclasses
-dontobfuscate
-forceprocessing
-optimizationpasses 5
-keep class * extends android.app.Activity
-assumenosideeffects class android.util.Log {
public static *** d(...);
public static *** v(...);
}
所以你会保存这一文件,然后打电话给ProGuard从蚂蚁,穿在你只编译的罐子和平台的罐子你使用。
也参看 例 在ProGuard手册。
更新(4.5年后): 如今我用 木材 对于安卓记录。
它不仅是一位好于默认的 Log
执行日志标记是自动设定,并且很容易登录的格式和串的例外情况—但你也可以指定不同的行为记录在运行时间。
在本示例中,记录的发言将只能写到调整你在调试版本的我的程序:
木材是设在我的 Application
onCreate()
方法:
if (BuildConfig.DEBUG) {
Timber.plant(new Timber.DebugTree());
}
然后其他地方,在我的代码,我可以容易日志:
Timber.d("Downloading URL: %s", url);
try {
// ...
} catch (IOException ioe) {
Timber.e(ioe, "Bad things happened!");
}
看看 木材样本应用程序 为了更先进的例子,在那里所有的日志发言发送给用,不知道如果在开发期间和在生产中,没有调试声明记录,但错误是默默的报告Crashlytics.
其他提示
所有好的答案,但是当我和我的开发完成我didn't想如果周围所有的日志调用语句既可以使用,也没有我想使用外部工具。
所以我真的使用该溶液是用我自己的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);
}
}
我在所有的源文件做的唯一的事情是我自己的类来代替android.util.Log的进口。
我建议具有静态布尔某处表示是否记录:
class MyDebug { static final boolean LOG = true; }
那么无论你想登录你的代码,只是这样做:
if (MyDebug.LOG) { if (condition) Log.i(...); }
现在当设置MyDebug.LOG为假,则编译器将去掉这样的检查中的所有代码(因为它是一个静态最终,它知道在不使用的代码的编译时间。)
对于较大的项目,你可能要开始有对单个文件进行布尔值,能够根据需要方便地存在启用或禁用日志记录。例如,这些是各种记录常数我们在窗口管理器:
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的解决方案是最好的,但如果您有任何理由不喜欢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外壳执行这些行。如果使用Windows,得到一个UNIX层或使用等效的Windows命令)
我想添加一些关于将 Proguard 与 Android Studio 和 gradle 一起使用的精确性,因为我在从最终二进制文件中删除日志行时遇到了很多问题。
为了要做 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'
}
}
其实在默认情况下 proguard-android.txt
文件,使用两个标志禁用优化:
-dontoptimize
-dontpreverify
这 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(...);
}
我强烈建议使用木从杰克沃顿
https://github.com/JakeWharton/timber
它可以解决您的问题与启用/禁用自动的加标签添加类
刚
public class MyApp extends Application {
public void onCreate() {
super.onCreate();
//Timber
if (BuildConfig.DEBUG) {
Timber.plant(new DebugTree());
}
...
日志将只在你的调试版本中使用,然后使用
Timber.d("lol");
或
Timber.i("lol says %s","lol");
打印
“你的类/ msg” 中没有specyfing标签
我用一个 LogUtils 类似谷歌IO例应用程序。我修改这一使用的应用程序的具体调试不断,而不是BuildConfig.因为调试 BuildConfig.调试是不可靠的.然后在我的班我有以下几点。
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");
}
}
我会考虑使用的代替roboguice的日志记录功能内置Android .util.Log
他们的设施自动禁用调试和详细日志发布版本。 另外,你可以使用一些漂亮的功能(例如定制的日志记录行为,额外的数据,每个日志等等)
使用ProGuard可能是相当麻烦,我也不会通过配置和使用你的应用程序使得它的工作的麻烦去,除非你有一个很好的理由(禁用日志不是好一个)
我张贴这个解决方案,它专为Android Studio用户适用。最近我还发现木材,并通过执行以下操作成功地导入到我的应用程序:
把最新版本的库到您的build.gradle:
compile 'com.jakewharton.timber:timber:4.1.1'
然后在Android的工作室,去编辑 - >查找 - >在路径替换...
键入Log.e(TAG,
或无论你定义了你的日志信息到"Text to find"
文本框。然后,你只是Timber.e(
更换
点击查找,然后全部更换。
Android的工作室现在将通过项目中的所有文件,并与木材取代所有的日志。
我不得不用这种方法唯一的问题是,它的gradle拿出百万难熬的错误消息之后,因为它无法找到每个Java文件中的进口“木材”。只需点击错误和Android工作室会自动导入“木材”到你的Java。一旦你已经做了所有你的错误文件,gradle这个会重新编译。
您也需要把这段代码在你onCreate
类的你Application
方法:
if (BuildConfig.DEBUG) {
Timber.plant(new Timber.DebugTree());
}
这将导致应用程序日志只有当你在发展方式尚未投入生产。您也可以BuildConfig.RELEASE
在释放模式登录。
每android.util.Log提供一种方式来启用/禁用日志:
public static native boolean isLoggable(String tag, int level);
默认isLoggable(...)方法返回false,则在设备setprop后才喜欢这样的:
adb shell setprop log.tag.MyAppTag DEBUG
这意味着任何日志以上DEBUG水平可以被打印出来。参考机器人DOC:
检查日志用于指定标签是否是在规定的电平为loggable。任何标签的默认级别设置 为INFO。这意味着,上述和包括INFO任何水平将是 登录。在进行任何调用一个测井方法,你应该检查 看看你的标签应该被记录下来。您可以更改默认级别 通过设置系统属性:“setprop log.tag。 “ 其中level或者是冗长,DEBUG,INFO,WARN,ERROR,ASSERT,或 压制。 SUPPRESS将关闭所有日志记录您的标记。您可以 还创建与它下面的一个local.prop文件: 'log.tag。=' 并将其放置在/data/local.prop。
因此,我们可以使用自定义日志UTIL:
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);
}
}
如果您可以运行全局替换(一次),之后保存一些编码约定,你可以按照经常在Android中的框架。
而不是写的
Log.d(TAG, string1 + string2 + arg3.toString());
它作为
if (BuildConfig.DEBUG) Log.d(TAG, string1 + String.format("%.2f", arg2) + arg3.toString());
现在proguard的可除去的StringBuilder和它使用的方式,从最优化释放DEX所有字符串和方法。使用proguard-android-optimize.txt
,你不需要担心的 android.util.Log 的在您的proguard-rules.pro
:
android {
…
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
使用过Android Studio插件的gradle,BuildConfig.DEBUG
是相当可靠的,所以你不需要额外的常量来控制剥离。
我有一个很简单的解决办法。我用的IntelliJ发展,所以细节不同,但思路应该在所有IDE的申请。
我挑我的源代码树的根目录,右击并选择做“替换”。那么,我选择全部替换“日志”。以 “//日志”。这将删除所有日志报表。把他们回来以后我再重复同样的替换,但这次作为全部替换“//日志”。用 “日志”。。
作品好了我。不过,别忘了设置替换为区分大小写,以避免事故的发生,如“对话”。为了增加保证你也可以做的第一步“日志”。作为要搜索的字符串。
辉煌。
如 zserge的评论的建议,
木材是非常好的,但如果你已经有一个现成的项目 - 您可以尝试github.com/zserge/log。这是一个下拉更换为android.util.Log并有多数认为木材都有,甚至更多的功能。
他的日志库提供了简单的启用/禁用,如下日志打印开关。
另外,它的只有的要求来改变import
线,和的没有的需要改变Log.d(...);
声明。
if (!BuildConfig.DEBUG)
Log.usePrinter(Log.ANDROID, false); // from now on Log.d etc do nothing and is likely to be optimized with JIT
添加以下到您的 proguard的-rules.txt 文件
-assumenosideeffects class android.util.Log {
public static *** d(...);
public static *** w(...);
public static *** v(...);
public static *** i(...);
}
我已经在溶液上方通过提供用于不同的日志级别支持和通过自动改变日志级别取决于如果代码被实时设备上或在仿真器上运行的改善。
public class Log {
final static int WARN = 1;
final static int INFO = 2;
final static int DEBUG = 3;
final static int VERB = 4;
static int LOG_LEVEL;
static
{
if ("google_sdk".equals(Build.PRODUCT) || "sdk".equals(Build.PRODUCT)) {
LOG_LEVEL = VERB;
} else {
LOG_LEVEL = INFO;
}
}
/**
*Error
*/
public static void e(String tag, String string)
{
android.util.Log.e(tag, string);
}
/**
* Warn
*/
public static void w(String tag, String string)
{
android.util.Log.w(tag, string);
}
/**
* Info
*/
public static void i(String tag, String string)
{
if(LOG_LEVEL >= INFO)
{
android.util.Log.i(tag, string);
}
}
/**
* Debug
*/
public static void d(String tag, String string)
{
if(LOG_LEVEL >= DEBUG)
{
android.util.Log.d(tag, string);
}
}
/**
* Verbose
*/
public static void v(String tag, String string)
{
if(LOG_LEVEL >= VERB)
{
android.util.Log.v(tag, string);
}
}
}
的ProGuard会为你做你的发布版本,现在从android.com好消息:
http://developer.android.com/tools/help/proguard.html
在ProGuard的工具压缩,优化并且通过去除未使用的代码和重命名类,字段和方法与语义隐晦的名称混淆代码。结果是较小尺寸的.apk文件是比较难以逆转工程师。由于ProGuard的使您的应用程序更难进行逆向工程,你当你的应用程序使用是敏感的安全,当您的许可使用应用程序,如功能,使用它是很重要的。
的ProGuard已集成到Android编译系统,让您不必手动调用它。 ProGuard的运行,只有当你建立在发布模式下您的应用程序,让你不必应付混淆代码,当你建立在调试模式下您的应用程序。具有ProGuard的运行完全是可选的,但值得推荐。
此文档描述了如何启用和配置的ProGuard以及使用回扫工具解码混淆堆栈跟踪
我喜欢使用Log.d(TAG,一些字符串,通常是一个的String.format())。
标签始终是类名
变换Log.d(TAG, - >的logD(在你的类的文本
private void Logd(String str){
if (MainClass.debug) Log.d(className, str);
}
在这种方式,当你准备做一个发布版本,MainClass.debug设置为false!
日志:
find . -name "*\.java" | xargs sed -ri ':a; s%Log\.[ivdwe].*\);%;%; ta; /Log\.[ivdwe]/ !b; N; ba'
Works的多行的日志。在这个解决方案可以肯定,该日志中不存在的生产代码。
我知道这是一个老问题,但你为什么不更换所有的日志,像调用 布尔logCallWasHere = TRUE; // ---你的日志在这里休息
这就是为什么你会知道,当你想要把他们回来,他们将不会影响你的if语句调用:)
为什么不只是做
if(BuildConfig.DEBUG)
Log.d("tag","msg");
?不需要额外的库,这往往会搞砸你的项目和Java编译器不proguard的规则将只留下了字节代码,此调用当你发布版本。