在ProGuard优化期间删除未使用的字符串

Chr*_*Orr 31 android proguard

我在发布Android应用程序时包含此ProGuard配置去除调试日志语句:

-assumenosideeffects class android.util.Log {
    public static *** d(...);
    public static *** v(...);
}
Run Code Online (Sandbox Code Playgroud)

这可以按预期工作 - 我可以从ProGuard日志和Android日志输出中看到Log.d("This is a debug statement");被删除的调用.

但是,如果我在此阶段反编译应用程序,我仍然可以看到所有使用的String文字 - 即This is a debug statement在此示例中.

有没有办法String从字节码中删除不再需要的每个?

Eri*_*une 47

ProGuard可以删除简单的常量参数(字符串,整数等).所以在这种情况下,代码和字符串常量应该完全消失:

Log.d("This is a debug statement");
Run Code Online (Sandbox Code Playgroud)

但是,您可能已经观察到某些代码的问题,如下所示:

Log.d("The answer is "+answer);
Run Code Online (Sandbox Code Playgroud)

编译后,这实际上对应于:

Log.d(new StringBuilder().append("The answer is ").append(answer).toString());
Run Code Online (Sandbox Code Playgroud)

ProGuard版本4.6可以简化为:

new StringBuilder().append("The answer is ").append(answer).toString();
Run Code Online (Sandbox Code Playgroud)

因此,日志记录已经消失,但优化步骤仍然会留下一些麻烦.如果没有关于StringBuilder类的更深入的知识,简化这一点是非常棘手的.就ProGuard而言,可以说:

new DatabaseBuilder().setup("MyDatabase").initialize(table).close();
Run Code Online (Sandbox Code Playgroud)

对于人类来说,StringBuilder代码显然可以被删除,但是DatabaseBuilder代码可能不会.ProGuard需要逃逸分析和一些其他技术,这些技术还没有.

至于解决方案:您可以创建带有简单参数的其他调试方法,并让ProGuard删除它们:

MyLog.d("The answer is ", answer);
Run Code Online (Sandbox Code Playgroud)

或者,您可以尝试在每个调试语句前面加上ProGuard稍后可以评估为false的条件.此选项可能有点复杂,在调试标志的初始化方法上需要一些额外的-assumenosideeffects选项.


nir*_*nir 6

这是我们如何做到的 - 使用ant任务

<target name="base.removelogs">
    <replaceregexp byline="true">
        <regexp pattern="Log.d\s*\(\s*\)\s*;"/>
        <substitution expression="{};"/>
        <fileset dir="src/"><include name="**/*.java"/></fileset>
    </replaceregexp>
</target>
Run Code Online (Sandbox Code Playgroud)


小智 5

因为我没有足够的代表来直接评论蚂蚁任务答案,所以这里有一些更正,因为它证明与像詹金斯这样可以执行发布构建的CI服务器组合非常有用:

<target name="removelogs">
    <replaceregexp byline="true">
        <regexp pattern="\s*Log\.d\s*\(.*\)\s*;"/>
        <substitution expression="{};"/>
        <fileset dir="src">
            <include name="**/*.java"/>
        </fileset>
    </replaceregexp>
</target>
Run Code Online (Sandbox Code Playgroud)

'.' Log必须转义后才能转义为'.' 括号内部指向任何日志记录语句,而不仅仅是'\ s*'的空格.

由于我对RegEx没有多少经验,我希望这可以帮助处于相同情况的某些人使这个ant任务工作(例如在Jenkins上).