Компиляция с Proguard дает SimException: «несоответствие типа локальной переменной»

Когда я скомпилирую свое приложение для 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 

Как я могу исправить эту проблему?

Solutions Collecting From Web of "Компиляция с Proguard дает SimException: «несоответствие типа локальной переменной»"

Фактическая часть Proguard заканчивается, но затем dex больше не может преобразовать полученный байт-код. Dex неправильно считает LocalVariableTable . Эрик Лафортунэ – лучший источник, чтобы объяснить, почему (см. Его ответ).

Проблема уходит, если вы не только не запутываете, но и пропустите шаг оптимизации ( -dontoptimize ). Но вы хотите иметь это для уменьшения размера. Другой способ решить эту проблему – сбросить флаги отладки в javac и в dex . Единственная проблема заключается в том, что тогда у вас тоже не было бы правильных стеков. Вы получите строки stacktrace без информации о файле или номерах строк, таких как:

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

Вы можете сделать это, добавив debug="false" в тег javac в main-rules.xml ant main-rules.xml ( main-rules.xml вы можете скопировать часть в build.xml ). Это установит флаг javac -g:none . Вам также нужно настроить dex, и это сложнее сделать в предоставленном шаблоне муравья. Я скопировал макрос dex-helper , убедился, что он используется, и добавил тег условия, окружающий вызовы 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>; } 

Таким образом, вы можете выполнять частичную обфускацию и все равно иметь эквивалентные хорошие стеки. Я все же предлагаю вам создать и сохранить файлы сопоставления после выпуска.

Кроме всего -keepattributes LocalVariableTable,LocalVariableTypeTable вы не должны указывать -keepattributes LocalVariableTable,LocalVariableTypeTable и одинаково -keepparameternames (если вы -keepparameternames , это само по себе может также вызвать у вас проблемы). Обратите внимание, что во втором подразумевается первое, хотя из его имени может быть неясно, что оно влияет на атрибуты.

Лично, и с учетом других проблем с Proguard я решил сделать обфускацию, но уменьшил потерю информации о стеке. Я еще не пробовал предложение плугана.

Более подробную информацию вы можете найти здесь:

  • proguard.cfg

  • build.xml

Я столкнулся с той же проблемой после добавления флага -dontobfuscate в файл proguard.cfg.

Решение оказалось, что мне нужно было добавить это к моим оптимизации:

 !code/allocation/variable 

Это делает мою полную строку оптимизации такой:

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

Это ошибка в ProGuard. Его шаг оптимизации иногда не позволяет полностью обновить необязательные атрибуты «LocalVariableTable» и «LocalVariableTypeTable» внутри файлов классов. В Dalvik VM явно проверяются атрибуты отладки и отклоняются файлы классов, если они несовместимы.

Вы должны проверить, исправлена ​​ли последняя версия ProGuard. В противном случае вы должны удалить локальные имена переменных и типы из файлов классов. Вы можете попросить java-компилятор не генерировать их (например, «javac -g: none»). Вы также можете попросить ProGuard не хранить их (не указывать «-keepattributes LocalVariableTable, LocalVariableTypeTable»).

У меня только что появилось это на Windows «Android Studio», и отключение Instant Run заставило все работать снова.