Proguard很好地删除了琐碎的日志调用。 (使用assumenosideeffects
关键字)
但是它很难处理非平凡的日志调用。
“非平凡”我指的不仅仅是一个字符串
例如:Log.i(TAG,"velocity="+velocity)
“。
Proguard保留new StringBuilder("velocity=")
,并且附加变量保留值,不会掩盖该变量。它仅删除对Log的最终调用
字符串将保留在那里,浪费内存,cpu周期并帮助破解者理解代码。
因此,为了解决这个问题,我使用if(BuildConfig.DEBUG){...}
在我的应用程序中包装每个非平凡的调试日志调用。
但是使用if(..){..}
包装每个日志都很繁琐且容易出错
它当然不是干的(不要重复自己)。
有没有办法通过Proguard(或任何其他方式)标记完全删除的方法,包括所有调用方法?
类似的东西:
@proguard_purge
public static void vanishingDebug(String whatever) {
Log.i(TAG,whatever);
}
所以这个方法会被混淆器消失,并且对这个方法的所有调用也会以递归方式消失?
拟订一项
混淆将优化代码并删除未使用或排除的方法 但是代码编译会在方法调用中生成额外的字节代码 before ,并且即使在混淆之后,前面的代码将保留,并留下代码,例如:
new StringBuilder("velocity=").append(a)
(假设在编译时无法确定a
。要进行测试,请使用velocity=Math.random();
)
这使得混淆代码非常容易理解。
要重现此问题,您需要安装dex2jar将apk转换为jar,并JAD将jar转换为java代码。
你会看到真正留下的东西,并感到恐惧。
实施例
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i("TAG", "Simple Comment"); // << Disappears well!
double index = Math.random();
index++;
Log.i("TAG2", "log_index=" + index); // << hmm... (!)
// class with only log calls inside
new ReferencedClass();
// simple method call
MyLogger.notLog("no_log" + index); // << stays, as expected
// simple method call with only Log call inside (aka "Log Wrapper")
MyLogger.log("log" + index); // << stays, as expected
Log.i("TAG2", "This is random:" + Math.random()); // << stays, same as above
setContentView(R.layout.activity_main);
}
使用此混淆配置:
-assumenosideeffects class android.util.Log {
public static *** isLoggable(java.lang.String, int);
public static *** d(...);
public static *** v(...);
public static *** i(...);
public static *** w(...);
public static *** e(...);
}
对于可以对此进行反编译和反模糊处理的状态,它将被混淆:
protected void onCreate(Bundle paramBundle)
{
super.onCreate(paramBundle);
double d = 1.0D + Math.random();
new StringBuilder("log_index=").append(d).toString();
new b();
a.a("no_log" + d);
new StringBuilder("log").append(d).toString();
a.a();
new StringBuilder("This is random:").append(Math.random()).toString();
setContentView(2130903064);
}
答案 0 :(得分:2)
就我的研究而言,这一点根本无法做到。你可以做的是设置你的ant构建脚本。
<target name="-commentoutlogs">
<replaceregexp match="(Log\..*?;\s*\n)" replace="/*\1*/" flags="gs" byline="false">
<fileset dir="src">
<include name="**/*.java"/>
</fileset>
</replaceregexp>
</target>
<target name="-uncommentlogs">
<replaceregexp match="\/\*(Log\..*?;\s*\n)\*\/" replace="\1" flags="gs" byline="false">
<fileset dir="src">
<include name="**/*.java"/>
</fileset>
</replaceregexp>
</target>
这是一个简单的基于正则表达式的脚本,您可以在build.xml文件中使用它,将其添加到ant发布目标中,如下所示:
<target name="release"
depends="-uncommentlogsbefore, -commentoutlogs, -set-release-mode, -release-obfuscation-check, -package, -post-package, -release-prompt-for-password, -release-nosign, -release-sign, -uncommentlogsafter, -post-build"
description="Builds the application in release mode.">
</target>
当然你还需要创建一个名为uncommentlogs的目标,与uncommentlogs相同的主体
这基本上把/ *放在任何Log之前。和* /最近的);
答案 1 :(得分:2)
我得出结论,ProGuard无法知道StringBuilder
与他被要求删除的日志有关。
因此,无法使用ProGuard规则删除类型为
Log.i("TAG2", "This is random:" + Math.random());
它总是会产生一个带有剩余部分的混淆代码,可以将其解码为:
new StringBuilder("This is random:").append(Math.random()).toString();
消除残羹剩饭的唯一方法是用以下方式包装每个非平凡的日志调用:
if (BuildConfig.DEBUG) Log.i(...)
答案 2 :(得分:0)
您可以将以下规则添加到proguard文件中,以删除对 debug 日志打印输出的所有调用:
-assumenosideeffects class android.util.Log {
public static *** d(...); }
例如,以下代码中的所有行都将从模糊处理的jar文件中消失:
String logevent = "log event";
android.util.Log.d("Tag", "This is my ");
android.util.Log.d("Tag", "This is my " + logevent);
P.S。
如果您拥有它,请不要忘记删除或注释掉该行: -dontoptimize