可能重复:
在ProGuard优化期间删除未使用的字符串
我有一个包含许多日志语句的Android应用程序.我希望它们不会出现在发布版本中,所以我在proguard.cfg文件中使用了Proguard这样的东西:
-assumenosideeffects class android.util.Log {
public static *** d(...);
}
Run Code Online (Sandbox Code Playgroud)
但问题是有很多Log.d("something is " + something),虽然Log.d()语句正在从字节码中删除,但字符串仍然存在.
所以,按照这个答案,我创建了一个简单的包装类,类似于:
public class MyLogger {
public static void d(Object... msgs) {
StringBuilder log = new StringBuilder();
for(Object msg : msgs) {
log.append(msg.toString());
}
Log.d(TAG, log.toString());
}
}
Run Code Online (Sandbox Code Playgroud)
然后我编辑了我proguard.cfg:
-assumenosideeffects class my.package.MyLogger {
public static *** d(...);
}
Run Code Online (Sandbox Code Playgroud)
但是仍然可以在生成的字节码中找到字符串!
除此之外,我使用的proguard.cfg是Android SDK提供的标准.难道我做错了什么?
编辑:在检查生成的字节码之后,我看到字符串在那里,但它们并没有像我想的那样相互追加.它们存储在一个数组中.为什么?将它们作为变量参数传递给我的方法.看起来ProGuard不喜欢这样,所以我修改了我的记录器类,如下所示:
public static void d(Object a) {
log(a);
}
public static void d(Object a, Object b) {
log(a, b);
}
(... I had to put like seven d() methods ...)
private static void log(Object... msgs) {
(same as before)
}
Run Code Online (Sandbox Code Playgroud)
这很难看,但现在字符串中没有字符串.
这是ProGuard的某种错误/限制吗?或者只是我不理解它是如何工作的?
Eri*_*une 11
对于不同数量的参数,使用不同方法的解决方案可能是最方便的.具有可变数量的参数的单个方法会更好,但是当前版本的ProGuard不够智能,无法删除所有未使用的代码.
java编译器将可变数量的参数编译为单个数组参数.在调用方面,这意味着创建一个正确大小的数组,填充元素,并将其传递给方法.ProGuard看到正在创建数组,然后用于在其中存储元素.它还没有意识到它还没有用于实际有用的操作,方法调用就没了.结果,保留了数组创建和初始化.
如果您期望进行某些特定优化,则检查已处理的代码是一种很好的做法.
Proguard 对我也不起作用,而且我不喜欢围绕 Log 创建包装器,因此我测试了以下解决方案:
工作解决方案
final static boolean IsDebugging = false;
Run Code Online (Sandbox Code Playgroud)
并在您的代码中:
if(IsDebugging)
Log.i(TAG, "Debugging");
Run Code Online (Sandbox Code Playgroud)
考虑到您必须使用final关键字,以便 IsDebugging 在编译时变为真或假,并且日志字符串不会出现在最终字节码中。
不工作(IsDebugMode)
public static boolean IsDebugMode(Context context) {
PackageManager pm = context.getPackageManager();
PackageInfo pi;
try {
pi = pm.getPackageInfo(context.getPackageName(),0);
} catch (NameNotFoundException e) {
return false;
}
return (pi.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
}
Run Code Online (Sandbox Code Playgroud)
在我的代码中:
boolean IsDebugging = Utils.IsDebugMode(this);
if(IsDebugging)
Log.i(TAG, "Debugging");
Run Code Online (Sandbox Code Playgroud)
上述解决方案不会在 Logcat 中打印任何日志,但日志字符串已编译并存在于最终字节码中,这是错误的。
另一个解决方案是:
不工作(BuildConfid.DEBUG)
if(BuildConfig.DEBUG)
Log.i(TAG, "Debugging");
Run Code Online (Sandbox Code Playgroud)
这与 IsDebugMode 解决方案相同。它不打印任何内容,但字符串在最终字节码中。又坏了!
| 归档时间: |
|
| 查看次数: |
8935 次 |
| 最近记录: |