Android Gradle插件3.4.0(带有R8编译器)之后的日志语句

时间:2019-05-05 01:16:30

标签: android logging android-gradle

Android的新R8编译器detects and safely removes unused classes, fields, methods, and attributes from your app and its library dependencies等。

它还会删除Log语句吗?例如。如果我构建了Release APK并准备好启动,是否可以安全地将Log语句保留在我的应用中?

Log.d("LogStatement", variable.toString())

还是我每次将应用上传/更新到Google Play时都必须删除它们?

3 个答案:

答案 0 :(得分:0)

不,您完全可以通过Proguard Tools进行此操作。在build.gradle中,您可以启用Proguard

release {
        minifyEnabled true

        proguardFiles getDefaultProguardFile(
                'proguard-android-optimize.txt'),
                'proguard-rules.pro'
    }

修改proguard-rules.pro文件,该文件应位于标准Android应用程序目录下:

-assumenosideeffects class android.util.Log {
  public static *** v(...);
  public static *** d(...);
  public static *** i(...);
  public static *** w(...);
  public static *** e(...);
}

希望这个答案对您有所帮助。

答案 1 :(得分:0)

我不确定,如果您仍在寻找答案,但是不会删除,如果您使用apk分析器检查apk(使用映射文件以提高可读性),您会看到Log类会存在。就像@Younes Charfaoui提到的那样,您可以添加这些proguard规则将其删除。

答案 2 :(得分:0)

简短的回答:这取决于。

正如您在R8的这个问题上所看到的:https://issuetracker.google.com/issues/73708157

这取决于您使用的记录器。 当然,您必须定义适当的ProGuard规则。

使用Younes Charfaoui所述的ProGuard规则时,对记录器的呼叫将被删除。 仅在使用纯字符串时有效:

Log.d("LogTag", "My log statement");

->将被正确删除。

但是在记录时使用(自动)StringBuilder时:

Log.d("LogTag", "My log statement will show some variable: " + variable);

仅删除对记录器的呼叫。
这意味着,StringBuilder部分将在结果ByteCode中保持可见。
您必须当心,而不要使用任何自动的StringBuilders。
另一个例子:

@Override
public void onCreate(Bundle savedInstanceState) {
  Log.d("MyFragment::onCreate", "will be removed"); // will be dropped
  Log.d("MyFragment::onCreate::", savedInstanceState.toString()); // call for toString() will remain
}

请参阅:

invoke-virtual {p1}, Landroid/os/Bundle;->toString()Ljava/lang/String;

有些ProGuard规则仅受ProGuard支持,而R8尚不支持,这些规则很容易删除其余的StringBuilder:假定没有外部副作用,假定没有外部返回值。

与自动StringBuilder一起使用日志记录时,您具有:

  • 由于StringBuilder执行其操作而导致性能下降,并且结果未得到使用。
  • 削弱了混淆,因为由于调试日志语句中剩下的StringBuilder,任何试图反汇编apk并读取ByteCode的人都可能更容易理解混淆的代码。

要真正确保使用R8删除了您的日志记录代码,您有两个选择:

  • 使用支持消息构建的记录器库(例如slf4j),您可以在其中编写:
logger.debug("My log statement will show some variable: {} and maybe another one: {}", variable1, variable2);
  • 在每次调用记录器时都要进行测试(阅读丑陋的代码确实增加了代码的复杂性,即使您需要像sonarqube这样的静态代码分析也是如此)。
    Logger.SHOW_LOG必须是一个公共静态最终布尔值,其值为= false,因此代码优化将把整行检测为未使用的代码,并正确删除之间的所有内容。
if (Logger.SHOW_LOG) {
  logger.debug("My log statement will show some variable: " + variable1 + " and maybe another one: " + variable2);
}

另请参阅:http://www.slf4j.org/faq.html#logging_performance

如果您还认为R8应该和ProGuard一样使用,请加注以下问题之一:
Add support for Proguard 6 -assumenoexternalsideeffects optimization option
Add support for Proguard 6 -assumenoexternalreturnvalues optimization option
Improve unused StringBuilder elimination