用Proguard编译给出SimException:“局部variablestypes不匹配”

当我编译我的Android应用程序与Proguard启用时,我得到以下错误:

-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 

我该如何解决这个问题?

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

如果你不仅不混淆,问题也会消失,而且跳过优化步骤( -dontoptimize )。 但是你想要减小尺寸。 解决这个问题的另一种方法是将debugging标志放在javacdex 。 唯一的问题是,那么你也不会有正确的堆栈跟踪。 您将获得没有源文件信息或行号的堆栈跟踪行,例如:

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

你可以通过在ant main-rules.xml中的javac标签中添加debug="false"来完成这个main-rules.xml (你可能想main-rules.xml这个部分拷贝到一个build.xml )。 这将设置一个标志javac -g:none 。 您还必须configurationdex,这在提供的ant模板中很难做到。 我复制了dex-helpermacros,确保它正在被使用,并在dex调用周围添加了一个条件标记:

  <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>; } 

这样你可以做部分混淆,并且仍然有相当好的栈跟踪。 我仍然build议你创build并保持映射文件,但释放。

最重要的是,你不应该指定-keepattributes LocalVariableTable,LocalVariableTypeTable和相同的-keepparameternames (如果你做了混淆,这本身也可能让你陷入麻烦)。 请注意,第二个意味着第一个,即使它的名称可能不清楚它会影响属性。

就个人而言,鉴于Proguard的其他问题,我select了模糊处理,但是减less了追踪信息的丢失。 我还没有尝试@Plowman的build议。

欲了解更多详情,你可以在这里find我的版本控制项目文件

  • proguard.cfg

  • build.xml文件

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

解决scheme结束了,我需要将这添加到我的优化:

 !code/allocation/variable 

这使得我完整的优化string如下所示:

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

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

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

我刚刚在Windows的Android Studio上重新做了这个表单,并且禁用了Instant Run让事情再次起作用。