可能的重复:
在 ProGuard 优化期间删除未使用的字符串
我有一个包含数十条日志记录语句的 Android 应用程序。我希望它们不会出现在发布版本中,因此我在 proguard.cfg 文件中使用了 Proguard ,如下所示:
-assumenosideeffects class android.util.Log {
public static *** d(...);
}
但问题是有很多 Log .d("something is " + some),尽管 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());
}
}
然后我编辑了我的 proguard.cfg
:
-assumenosideeffects class my.package.MyLogger {
public static *** d(...);
}
但字符串仍然可以在生成的字节码中找到!
其他除此之外,我使用的是 Android SDK 提供的标准 proguard.cfg
。我做错了什么吗?
编辑:检查生成的字节码后,我看到字符串在那里,但它们并没有像我想象的那样被一个一个附加到另一个上。它们存储在数组中。为什么?将它们作为变量参数传递给我的方法。看起来 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)
}
它很难看,但现在字符串在字节码中无处。
这是 ProGuard 的某种错误/限制吗?或者只是我不明白它是如何工作的?
Possible Duplicate:
Removing unused strings during ProGuard optimisation
I have an Android application with dozens of logging statements. I'd prefer they wouldn't appear in the release version, so I used Proguard with something like this in the proguard.cfg
file:
-assumenosideeffects class android.util.Log {
public static *** d(...);
}
But the problem is that there are a lot of Log.d("something is " + something)
, and although the Log.d()
statement is being removed from the bytecode, the strings are still there.
So, following this answer, I created a simple wrapper class, something along the lines of:
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());
}
}
Then I edited my proguard.cfg
:
-assumenosideeffects class my.package.MyLogger {
public static *** d(...);
}
But the strings are still found in the generated bytecode!
Other than this, I am using the standard proguard.cfg
provided by the Android SDK. Am I doing something wrong?
Edit: after examining the generated bytecode, I saw that the strings were there, but they were not being appended one to another, as I thought. They were being stored in an array. Why? To pass them as variable parameters to my method. It looks like ProGuard doesn't like that, so I modified my logger class like this:
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)
}
It's ugly, but now the strings are nowhere in the bytecode.
Is this some kind of bug/limitation of ProGuard? Or is it just me not understanding how it works?
发布评论
评论(2)
针对不同数量的参数使用不同方法的解决方案可能是最方便的解决方案。具有可变数量参数的单个方法会更好,但当前版本的 ProGuard 不够智能,无法删除所有未使用的代码。
java 编译器将可变数量的参数编译为单个数组参数。在调用方面,这意味着创建一个正确大小的数组,填充元素,并将其传递给方法。 ProGuard 看到数组正在被创建,然后用于在其中存储元素。它(还)没有意识到它没有用于实际有用的操作,方法调用也消失了。因此,数组的创建和初始化被保留。
如果您期望进行某些特定的优化,那么检查已处理的代码是一个很好的做法。
Your solution with different methods for different numbers of arguments is probably the most convenient one. A single method with a variable number of arguments would be nicer, but the current version of ProGuard is not smart enough to remove all the unused code.
The java compiler compiles a variable number of arguments as a single array argument. On the invocation side, this means creating an array of the right size, filling out the elements, and passing it to the method. ProGuard sees that the array is being created and then being used to store elements in it. It doesn't realize (yet) that it then isn't used for actual useful operations, with the method invocation being gone. As a result, the array creation and initialization are preserved.
It's a good practice to check the processed code if you're expecting some particular optimization.
Proguard 对我也不起作用,而且我不喜欢围绕 Log 创建包装器,因此我测试了以下解决方案:
WORKING Solution
并在您的代码中:
考虑您必须使用final 关键字,以便 IsDebugging 在编译时变为 true 或 false,并且日志字符串不会出现在最终字节码中。
不工作(IsDebugMode)
并且在我的代码中:
上述解决方案不会在 Logcat 中打印任何日志,但日志字符串已编译并存在于最终字节码中,这是不好的。
另一个解决方案是:
NOT WORKING (BuildConfid.DEBUG)
这与 IsDebugMode 解决方案相同。它不打印任何内容,但字符串位于最终字节码中。又坏了!
Proguard doesn't work me, too, and I don't like to create a wrapper around Log, so I've tested the following solutions:
WORKING Solution
and in your code:
consider that you must use final keyword so that IsDebugging become true or false at compile time and log strings doesn't appear in final bytecode.
NOT WORKING (IsDebugMode)
and in my code:
The above solution doesn't print any Log in Logcat but the log string are compiled and exist in final bytecode which is bad.
The other solution was :
NOT WORKING (BuildConfid.DEBUG)
This is same as IsDebugMode solution. It doesn't print anything but strings are in final bytecode. Bad again!