【问题标题】:Proguard and XStream with omitField() on Android在 Android 上使用 omitField() 的 Proguard 和 XStream
【发布时间】:2011-09-19 02:02:13
【问题描述】:

我在我的 Android 应用程序中使用 XStream 对 xml 进行反序列化,现在我正在努力将 Proguard(混淆器)添加到组合中。

这是我遇到的运行时异常(完整:pastebin):

WARN/System.err(6209): net.lp.collectionista.util.a.g: XStream could not parse the response
WARN/System.err(6209):     at net.lp.collectionista.a.s.a(Collectionista:215)
    ...
WARN/System.err(6209): Caused by: com.thoughtworks.xstream.converters.ConversionException: id : id in loader dalvik.system.PathClassLoader[/data/app/net.lp.collectionista-2.apk] : id : id in loader dalvik.system.PathClassLoader[/data/app/net.lp.collectionista-2.apk]
WARN/System.err(6209): ---- Debugging information ----
WARN/System.err(6209): message             : id : id in loader dalvik.system.PathClassLoader[/data/app/net.lp.collectionista-2.apk]
WARN/System.err(6209): cause-exception     : com.thoughtworks.xstream.mapper.CannotResolveClassException
WARN/System.err(6209): cause-message       : id : id in loader dalvik.system.PathClassLoader[/data/app/net.lp.collectionista-2.apk]
WARN/System.err(6209): class               : net.lp.collectionista.jaxb.googlebooks.search.Feed
WARN/System.err(6209): required-type       : java.lang.Object
WARN/System.err(6209): path                : /feed/entry/id
WARN/System.err(6209): line number         : 1
WARN/System.err(6209): -------------------------------
WARN/System.err(6209):     at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(Collectionista:89)
    ...
WARN/System.err(6209):     at com.thoughtworks.xstream.XStream.fromXML(Collectionista:861)
    ...
WARN/System.err(6209): Caused by: com.thoughtworks.xstream.mapper.CannotResolveClassException: id : id in loader dalvik.system.PathClassLoader[/data/app/net.lp.collectionista-2.apk]
WARN/System.err(6209):     at com.thoughtworks.xstream.mapper.DefaultMapper.realClass(Collectionista:68)
    ...

不用说,没有 Proguard 也能正常工作。我在这里使用了缩小、优化和混淆,尽管我在任何 XStream 类以及任何代表 xml 字段模型的类上都禁用了它:

-keep class net.lp.collectionista.jaxb.** { *; }
-keep class com.thoughtworks.xstream.** { *; }

我可以从混淆的 jar 以及 mapping.txt(用于方法)中确认,提到的任何类都存在并且没有被混淆,因此未触及 AFAICT。我也保留注释。

我很清楚这个例外。我有:

        xstream.omitField(Feed.class, "id");

等等。由于 Proguard,omitField() 调用似乎不再起作用,它开始寻找“id”模型类。这就是我被卡住的地方,即使在深入研究 XStream 代码之后也是如此。混淆的最终结果中的整个 omitField 调用似乎是完整的,那么这里还有什么可以破坏的呢?它也不应该是“Feed.class”,因为那个也仍然存在。我错过了什么?调试的下一步是什么?

编辑:我确实注意到我的混淆 jar 中的 xstream 类的类文件比原始的略小,即使使用 -dontoptimize。什么还在被丢弃?

EDIT2:我开始认为这与缺少类似于以下的 dex 警告有关:

[apply] warning: Ignoring InnerClasses attribute for an anonymous inner class
[apply] (com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter$1) that doesn't come with an
[apply] associated EnclosingMethod attribute. This class was probably produced by a
[apply] compiler that did not target the modern .class file format. The recommended
[apply] solution is to recompile the class from source, using an up-to-date compiler
[apply] and without specifying any "-target" type options. The consequence of ignoring
[apply] this warning is that reflective operations on this class will incorrectly
[apply] indicate that it is *not* an inner class.

...也许不是...

EDIT3: 最后,尽管处理了许多其他错误和问题,例如the SimException bug,但我仍然能够在一些有限的情况下使其正常工作。这样我就可以将其精确定位到混淆步骤。也就是说,至少,如果我添加“-dontobfuscate”,问题就会消失。这不是我第一次玩这个,所以它必须是其他问题的解决方法,或者更窄的配置,也可以缓解这个问题。所以我再次问:当我已经使用“-keep”保护了 xstream 的主要部分和我的模型类免受混淆时,还有什么可能造成这种混乱?

如果您需要更多信息,请告诉我。

【问题讨论】:

    标签: android obfuscation deserialization xstream proguard


    【解决方案1】:

    正如我所说,如果您-dontobfuscate,问题就会消失,但我们假设您不希望这样。

    解决办法是保留更多属性:

    -keepattributes EnclosingMethod, InnerClasses
    -keepattributes *Annotation*
    -keepattributes Signature
    

    一旦您开始使用它,您就可以缩小要保留的 XStream 代码部分的范围。我有:

    -keep class com.thoughtworks.xstream.converters.extended.SubjectConverter { *; }
    -keep class com.thoughtworks.xstream.converters.extended.ThrowableConverter { *; }
    -keep class com.thoughtworks.xstream.converters.extended.StackTraceElementConverter { *; }
    -keep class com.thoughtworks.xstream.converters.extended.CurrencyConverter { *; }
    -keep class com.thoughtworks.xstream.converters.extended.RegexPatternConverter { *; }
    -keep class com.thoughtworks.xstream.converters.extended.CharsetConverter { *; }
    
    -keep class com.thoughtworks.xstream.annotations.** { *; }
    

    您还可以禁用很多与 XStream 相关的警告。

    有关更多详细信息,您可以在此处找到我的版本控制项目文件:

    【讨论】:

    • 禁用 XStream 警告会很危险(前提是我永远不会替换我的 XStream jars)?我的意思是,它会导致将来出现任何难以发现的错误吗?
    • 是的,我相信,当警告不是误报时,你会错过它们。
    【解决方案2】:

    我似乎是许多在使用 ProGuard 和 XStream for Android 时遇到问题的人之一。经过一些试验和研究,以下是对我有用的 - 一个完整的配置文件以及一些解释性的 cmets 为什么我这样做了。请注意,我的首要任务是混淆,但我不太关心优化或缩小。

    并且您需要记住,使用此配置(保留库的公共成员 - 见下文)您将需要为 XStream 用于创建 XML 的类使用“公共”成员,因为 XStream 将使用成员XML 标签的名称 - 而且您不希望您的 XML 标签更改为“a”、“b”或“c”:) 祝你好运!

    ###########################################################
    #
    # FLAGS
    #
    ###########################################################
    
    
    # Not sure if I need this one, but seems to do no harm
    -keepdirectories
    
    # I needed NOT to optimize for SWT or XStream would not work, but for Android I do not seem to need to do that.
    # However, if I try to shrink, XStream fails for Android. This different behaviour is a bit odd and black magic.
    # However, I do not much care about optimization or size, and stability is more important for me, so let's
    # neither optimize nor shrink (and shrinking saved us only about 1.5% of the size anyway).
    #
    # Note: this was not all that was necessary to make XStream run for Android - see other comments
    # (search for XStream)
    -dontshrink
    -dontoptimize
    # The following was configured for Android by default but now it does not make sense because I do not optmize, so disable just in case.
    # -optimizationpasses 5
    
    # Not sure if I need this one, but seems to do no harm.
    -keeppackagenames
    
    # This was configured for Android by default and it can only help.
    -dontusemixedcaseclassnames
    
    # This was configured for Android by default, and it is the default option as of ProGuard 4.5 anyway.
    -dontskipnonpubliclibraryclasses
    
    # ProGuard documentation says:
    # For Java 6, preverification is optional, but as of Java 7, it is required.
    # Only when eventually targeting Android, it is not necessary, so you can then
    # switch it off to reduce the processing time a bit.
    -dontpreverify
    
    # Specifies to write out some more information during processing. If the
    # program terminates with an exception, this option will print out the
    # entire stack trace, instead of just the exception message.
    -verbose
    
    # Since I have turned off optmization, it makes no sense to have the following
    # option enabled.
    #-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
    
    # The followig was necessary or it would not build, as it otherwise wants a totally clean build first.
    -ignorewarnings
    
    ###########################################################
    #
    # -keep SPECIFICATIONS
    #
    ###########################################################
    
    # I tried adding those to fix the XStream problem, but in the end fixed it differently (see other comments).
    #-keepattributes EnclosingMethod, InnerClasses
    #-keepattributes *Annotation*
    #-keepattributes Signature
    
    # The following was configured for Android by default.
    -keep public class * extends android.app.Activity
    -keep public class * extends android.app.Application
    -keep public class * extends android.app.Service
    -keep public class * extends android.content.BroadcastReceiver
    -keep public class * extends android.content.ContentProvider
    -keep public class * extends android.app.backup.BackupAgentHelper
    -keep public class * extends android.preference.Preference
    -keep public class com.android.vending.licensing.ILicensingService
    
    # I tried adding those to fix the XStream problem, but in the end fixed it differently (see other comments).
    # However, it might still be a good idea to stay away from thoughtworks for stability's sake.
    # (Not sure if the second keep does not include the first one.)
    -keep class com.thoughtworks.xstream.*
    -keep class com.thoughtworks.xstream.* {
        public protected <methods>;
        public protected <fields>;
    }
    
    # The following plus not-shrinking seems necessary to make XStream run for Android.
    # But again, as for SWT, I did not need to exclude all, public and protected methods and fields:
    # just doing the public fields was enough.
    #    public protected <methods>;
    #    public protected <fields>;
    -keep public class * {
        public <fields>;
    }
    
    # This was configured for Android by default - and very necessary it is too.
    -keepclassmembers enum * {
        public static **[] values();
        public static ** valueOf(java.lang.String);
    }
    
    # I put it in because we might need this one in the future.
    # This was default for the Windows installation of ProGuard, which said:
    # Also keep - Database drivers. Keep all implementations of java.sql.Driver.
    -keep class * extends java.sql.Driver
    
    # This was configured for Android by default.
    -keepclasseswithmembernames class * {
        native <methods>;
    }
    
    # This was configured for Android by default.
    -keepclasseswithmembers class * {
        public <init>(android.content.Context, android.util.AttributeSet);
    }
    
    # This was configured for Android by default.
    -keepclasseswithmembers class * {
        public <init>(android.content.Context, android.util.AttributeSet, int);
    }
    
    # This was configured for Android by default.
    -keepclassmembers class * extends android.app.Activity {
       public void *(android.view.View);
    }
    
    # This was configured for Android by default.
    -keep class * implements android.os.Parcelable {
      public static final android.os.Parcelable$Creator *;
    }
    

    【讨论】:

    • 谢谢。不过,我不确定我是否能很快尝试一下。您能否突出显示与接受的答案不同的方法和/或为什么接受的答案不正确/不完整?
    【解决方案3】:

    XStream 似乎对 EnclosureMethod 属性进行了自省,因此将其保留在您的 ProGuard 配置中可能会有所帮助:

    -keepattributes EnclosingMethod
    

    ProGuard manual 提供了您可能希望保留的属性列表。错误消息表明您已经保留了 InnerClasses 属性,这可能确实是必需的。

    【讨论】:

    • 您好,埃里克,感谢您的回答。我已经保留了 EnclosureMethod 以及所有 Annotations 属性。还能是别的吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-25
    • 2015-01-20
    • 1970-01-01
    • 1970-01-01
    • 2012-04-08
    • 1970-01-01
    相关资源
    最近更新 更多