用Proguard编译给出SimException:“局部变量类型不匹配”

时间:2011-04-18 09:50:29

标签: android proguard

当我在启用Proguard的情况下编译我的Android应用程序时,出现以下错误:

-dex:
 [echo] Converting compiled files and external libraries into /home/ka/dev/workspace/ImPress/build/classes.dex...
[apply] 
[apply] UNEXPECTED TOP-LEVEL EXCEPTION:
[apply] com.android.dx.cf.code.SimException: local variable type mismatch: attempt to set or access a value of type java.io.File using a local variable of type java.lang.Object[]. This is symptomatic of .class transformation tools that ignore local variable information.
[apply]     at com.android.dx.cf.code.BaseMachine.throwLocalMismatch(BaseMachine.java:550)
[apply]     at com.android.dx.cf.code.BaseMachine.getLocalTarget(BaseMachine.java:405)
[apply]     at com.android.dx.cf.code.BaseMachine.storeResults(BaseMachine.java:532)
[apply]     at com.android.dx.cf.code.ValueAwareMachine.run(ValueAwareMachine.java:197)
[apply]     at com.android.dx.cf.code.RopperMachine.run(RopperMachine.java:291)
[apply]     at com.android.dx.cf.code.Simulator$SimVisitor.visitLocal(Simulator.java:608)
[apply]     at com.android.dx.cf.code.BytecodeArray.parseInstruction(BytecodeArray.java:526)
[apply]     at com.android.dx.cf.code.Simulator.simulate(Simulator.java:99)
[apply]     at com.android.dx.cf.code.Ropper.processBlock(Ropper.java:684)
[apply]     at com.android.dx.cf.code.Ropper.doit(Ropper.java:639)
[apply]     at com.android.dx.cf.code.Ropper.convert(Ropper.java:252)
[apply]     at com.android.dx.dex.cf.CfTranslator.processMethods(CfTranslator.java:252)
[apply]     at com.android.dx.dex.cf.CfTranslator.translate0(CfTranslator.java:131)
[apply]     at com.android.dx.dex.cf.CfTranslator.translate(CfTranslator.java:85)
[apply]     at com.android.dx.command.dexer.Main.processClass(Main.java:369)
[apply]     at com.android.dx.command.dexer.Main.processFileBytes(Main.java:346)
[apply]     at com.android.dx.command.dexer.Main.access$400(Main.java:59)
[apply]     at com.android.dx.command.dexer.Main$1.processFileBytes(Main.java:294)
[apply]     at com.android.dx.cf.direct.ClassPathOpener.processArchive(ClassPathOpener.java:244)
[apply]     at com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:130)
[apply]     at com.android.dx.cf.direct.ClassPathOpener.process(ClassPathOpener.java:108)
[apply]     at com.android.dx.command.dexer.Main.processOne(Main.java:313)
[apply]     at com.android.dx.command.dexer.Main.processAllFiles(Main.java:233)
[apply]     at com.android.dx.command.dexer.Main.run(Main.java:185)
[apply]     at com.android.dx.command.dexer.Main.main(Main.java:166)
[apply]     at com.android.dx.command.Main.main(Main.java:90)
[apply] ...at bytecode offset 00000006
[apply] locals[0000]: Lcom/officemax/impress/ui/library/task/DocumentBrowserTask;
[apply] locals[0001]: [Ljava/lang/Object;
[apply] locals[0002]: <invalid>
[apply] ...while working on block 0006
[apply] ...while working on method doTaskJob:([Ljava/lang/Object;)Lcom/kaciula/utils/ui/BasicTaskResponse;
[apply] ...while processing doTaskJob ([Ljava/lang/Object;)Lcom/kaciula/utils/ui/BasicTaskResponse;
[apply] ...while processing com/officemax/impress/ui/library/task/DocumentBrowserTask.class
[apply] 
[apply] 1 error; aborting

如何解决此问题?

4 个答案:

答案 0 :(得分:97)

在我的proguard.cfg文件中添加了-dontobfuscate标志后,我遇到了同样的问题。

最终解决方案是我需要将其添加到我的优化中:

!code/allocation/variable

这使我的完整优化字符串看起来像这样:

-optimizations !field/removal/writeonly,!field/marking/private,!class/merging/*,!code/allocation/variable

答案 1 :(得分:22)

这是ProGuard中的一个错误。其优化步骤有时不会完全正确地更新类文件中的可选“LocalVariableTable”和“LocalVariableTypeTable”调试属性。 Dalvik VM显式检查调试属性,如果类文件不一致则拒绝它们。

您应该检查最新版本的ProGuard是否解决了问题。否则,您应该从类文件中删除局部变量名称和类型。您可以要求java编译器不生成它们(例如“javac -g:none”)。您也可以要求ProGuard不要保留它们(不要指定“-keepattributes LocalVariableTable,LocalVariableTypeTable”)。

答案 2 :(得分:15)

实际的Proguard部分完成,但是dex无法再转换生成的字节码。 Dex认为LocalVariableTable不正确。 Eric Lafortune是解释原因的更好来源(见他的回答)。

如果您不仅不进行模糊处理,而且还跳过优化步骤(-dontoptimize),问题就会消失。但是你想要减小尺寸。另一种解决方法是删除javacdex中的调试标志。唯一的问题是,你也没有适当的堆栈跟踪。您将获得没有源文件信息或行号的stacktrace行,例如:

net.lp.collectionista.domain.items.book.BookItem.getCoverImageForFormField(Unkno‌​wn Source)

您可以在ant debug="false"的{​​{1}}标记中添加javac来执行此操作(您可能需要先将部分复制到main-rules.xml)。这将设置标志build.xml。您还必须配置dex,这在提供的ant模板中更难做到。我复制了javac -g:none宏,确保它被使用,并添加了一个围绕dex调用的条件标记:

dex-helper

这是 <echo>Converting compiled files and external libraries into ${intermediate.dex.file}...</echo> <if condition="debug"> <then> <apply executable="${dx}" failonerror="true" parallel="true"> <arg value="--dex" /> <arg value="--output=${intermediate.dex.file}" /> <extra-parameters /> <arg line="${verbose.option}" /> <arg path="${out.dex.input.absolute.dir}" /> <path refid="out.dex.jar.input.ref" /> <external-libs /> </apply> </then> <else> <apply executable="${dx}" failonerror="true" parallel="true"> <arg value="--dex" /> <arg value="--output=${intermediate.dex.file}" /> <arg value="--no-locals" /><!-- otherwise dex fails on the proguard bytecode --> <extra-parameters /> <arg line="${verbose.option}" /> <arg path="${out.dex.input.absolute.dir}" /> <path refid="out.dex.jar.input.ref" /> <external-libs /> </apply> </else> </if>

为了减少您可以使用的堆栈跟踪信息的丢失,分别用于行号信息以及类和方法名称信息:

--no-locals

通过这种方式,您可以进行部分混淆,并且仍然具有相同的良好堆栈跟踪。我仍然建议您在发布时创建并保留映射文件。

除此之外,你不应该指定-keepattributes SourceFile, LineNumberTable -keep,allowshrinking,allowoptimization class * { <methods>; } -keepattributes LocalVariableTable,LocalVariableTypeTable(如果你做混淆,这本身也可能会让你陷入麻烦)。请注意,第二个意味着第一个,即使它的名称可能不清楚它会影响属性。

就个人而言,鉴于Proguard的其他问题,我选择进行混淆,但减少了堆栈跟踪信息的丢失。我还没有尝试过@plowman的建议。

有关详细信息,请在此处找到我的版本控制项目文件:

答案 3 :(得分:6)

我刚刚在Windows上重现了这个问题。 Android Studio和禁用Instant Run使得事情再次发挥作用。