Компиляция с Proguard дает SimException: "несоответствие типа локальной переменной" - PullRequest
46 голосов
/ 18 апреля 2011

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

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

Ответы [ 4 ]

98 голосов
/ 28 сентября 2011

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

В итоге я решил добавить это к своим оптимизациям:

!code/allocation/variable

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

-optimizations !field/removal/writeonly,!field/marking/private,!class/merging/*,!code/allocation/variable
22 голосов
/ 20 апреля 2011

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

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

15 голосов
/ 02 ноября 2011

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

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

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

Вы можете сделать это, добавив debug="false" в тег javac в муравье 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.

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

6 голосов
/ 12 мая 2016

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

...