Компиляция с 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

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


person Catalin Morosan    schedule 18.04.2011    source источник
comment
В итоге я сообщил об этом, потому что чувствовал, что это было лучше, чем игнорировать и без того тихую проблему: sourceforge.net/tracker/   -  person pjv    schedule 26.06.2011
comment
Пожалуйста, дайте мне знать, когда найдете решение этой проблемы. Мне действительно нужно сжать мои приложения, потому что я использую много библиотек.   -  person Catalin Morosan    schedule 30.06.2011
comment
Я закрыл ошибку. Я думаю, нам придется жить с обходными путями.   -  person pjv    schedule 02.11.2011


Ответы (4)


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

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

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

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

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

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

person pjv    schedule 02.11.2011
comment
Когда вы используете gradle, вы можете добавить следующий бит, чтобы добавить параметр --no-locals к шагу dex: project.tasks.withType(com.android.build.gradle.tasks.Dex) { additionalParameters=['--no-locals'] } - person Johan Pelgrim; 16.09.2015
comment
Предлагаемый @ JohanPelgrim бит для добавления --no-locals можно поместить в блок buildTypes { release { в build.gradle модуля. Спасибо, Йохан! - person LarsH; 30.09.2015

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

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

!code/allocation/variable

В результате моя полная строка оптимизации выглядит так:

-optimizations !field/removal/writeonly,!field/marking/private,!class/merging/*,!code/allocation/variable
person plowman    schedule 28.09.2011
comment
Спасибо большое! Какое-то время я искал решение этой проблемы! - person alexanderblom; 09.01.2012
comment
Я даже не использовал -dontobfuscate, но получал ошибки, и только это изменение решило проблему для меня. Спасибо! - person mlc; 28.02.2012
comment
Было бы полезно, если бы кто-нибудь мог подтвердить, что это все еще происходит в ADT-20, который к настоящему времени использует более интеллектуальные способы работы с библиотеками, а также в ProGuard 4.7. И этот метод решает эту проблему. Решение, которое я описал выше, устарело, потому что build.xml был сильно изменен, хотя принцип все еще применяется. - person pjv; 11.06.2012
comment
@pjv Я могу подтвердить, что он все еще работает на ADT-20, и что добавление! code / allocation / variable в мой локальный файл конфигурации ProGuard работает. Мой выглядит так: -оптимизации! Код / упрощение / арифметика,! Код / упрощение / приведение,! Поле / * ,! класс / объединение / *,! Код / распределение / переменная - person Matt Quigley; 12.07.2012
comment
Я видел эту ошибку с инструментами ADT SDK r21.1 и платформенными инструментами 16.0.2. Добавление !code/allocation/variable в оптимизацию устранило ошибку. - person James Wald; 06.03.2013
comment
Этот ответ исправил аналогичную ошибку для меня в Android Studio 1.2.2. Я получал сообщение об ошибке при попытке отладки, хотя в типе сборки отладки было minifyEnabled false - person John Cummings; 17.08.2015
comment
Подтверждая, что я получил эту ошибку в Android Studio 1.3.2, и этот ответ решил ее (как и @ pjv). - person LarsH; 30.09.2015
comment
Это снова в студии 2.3 с последними инструментами сборки Android 25.0.2 и скомпилировано для 25. - person JPM; 03.04.2017
comment
Спасибо большое. Вы спасли мою жизнь. :) - person JohnWatsonDev; 30.09.2017

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

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

person Eric Lafortune    schedule 19.04.2011
comment
Спасибо за ответ. Я добавил последнюю версию proguard, но проблема все еще существует. Это дает то же исключение, но в одной из моих банок. Тем не менее, в моем proguard.cfg у меня нет -keepattributes LocalVariableTable, LocalVariableTypeTable. Могу ли я как-то явно сказать, что я не хочу, чтобы proguard сохранял имена локальных переменных и т. Д.? - person Catalin Morosan; 21.04.2011
comment
Вы что-нибудь меняли в proguard.cfg? Возможно, вы добавили -dontobfuscate? - person Eric Lafortune; 27.04.2011
comment
dex имеет параметр --no-locals. Однако обновление jar-файлов в ‹android install› / tools / proguard / lib / до последней версии 4.6 устранило это для меня. (спасибо @Eric) Как ни странно, только сжатие (оптимизация) все еще показывает эти ошибки, но обфускация и сжатие вместе успешны. - person larham1; 14.05.2011
comment
@ Эрик, у вас есть отчет по отслеживанию ошибок Proguard? Я до сих пор не могу найти обходной путь (ничего из вышеперечисленного меня никуда не приведет), который позволяет мне сохранить -dontobfuscate, и мы не все специалисты по байт-коду Java. - person pjv; 23.06.2011
comment
Используя -g: none в javac (с помощью debug = false в целевой компиляции) и --no-locals в target -dex в ant, я мог бы обойти эту проблему, но она все еще ужасно пахнет. Я считаю, что одним ограничением сейчас является то, что мне нужно будет создать разные цели для вывода отладки (и это может работать только без proguard) и, возможно, некоторые проблемы с трассировкой стека. - person pjv; 23.06.2011
comment
Хорошо, теперь я действительно получаю трассировки стека без номеров строк, например: net.lp.collectionista.domain.items.book.BookItem.getCoverImageForFormField (Неизвестный источник). Но я, конечно, тоже не получаю файл сопоставления после оптимизации (и я использую -dontobfuscate). Как правильно получить трассировку стека? Для меня это проблема, так как мне нужно анализировать сбои, которые произошли на стороне пользователей. - person pjv; 25.06.2011
comment
У меня точно такая же проблема. Мне нужен -dontobfuscate для трассировки стека и прочего. Мне просто нужно уменьшить размер приложения. - person Catalin Morosan; 30.06.2011
comment
Есть новости по этому поводу? 4.8 не устраняет эту ошибку. РЕДАКТИРОВАТЬ: решение пахаря, добавив !code/allocation/variable, решило проблему - person Oleg Vaskevich; 11.06.2012

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

person JaviCasa    schedule 12.05.2016
comment
Спасибо! У меня была такая же проблема Android Studio 2.1.2 на OSX. Отключение Instant Run решило эту проблему. - person Gagege; 14.06.2016
comment
Это снова в студии 2.3 с последними инструментами сборки Android 25.0.2 и скомпилировано для 25. - person JPM; 03.04.2017