当我在启用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
如何解决此问题?
答案 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
),问题就会消失。但是你想要减小尺寸。另一种解决方法是删除javac
和dex
中的调试标志。唯一的问题是,你也没有适当的堆栈跟踪。您将获得没有源文件信息或行号的stacktrace行,例如:
net.lp.collectionista.domain.items.book.BookItem.getCoverImageForFormField(Unknown 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使得事情再次发挥作用。