Android obguascated proguard вызывает причину NullPointerException, когда это действительно не должно быть

Я распространил приложение на Android Marketplace. Я получаю отчеты об ошибках от небольшой части пользователей (возможно, 2%), где они получают NullPointerExceptions, где это не имеет логического смысла.

Я никогда не смог воспроизвести это сам. Код относительно прост и является общим кодовым путем, к которому должен следовать каждый пользователь. Я на самом деле взял каждую отдельную строку кода, которая могла бы создать NPE и обернуть ее в блок try-catch и выбросить исключение пользовательской среды выполнения, но я все еще не получаю ошибки NullPointerException.

На данный момент, единственное, что я могу себе представить, это что-то связанное с моей запутанностью Proguard. Я видел, как некоторые другие статьи говорили об извлечении опции -overloadaggressively, если вы заметили странное поведение, но, насколько я могу судить, я не использую этот параметр.

Кто-нибудь еще испытал таинственные NPE, используя андроид и пролога. Есть ли другие настройки, которые люди могут рекомендовать для набора оптимизаций, которые могут вызвать эту проблему?

Любые другие идеи?

Для справки, вот ненаблюдаемая функция, которая получает NPE:

public MainMenuScreen(final HauntedCarnival game) { super(game); game.startMusic("data/music/intro.mp3"); stage = new Stage(Screen.SCREEN_WIDTH, Screen.SCREEN_HEIGHT,true); stage.addActor(new Image("background", Assets.mainMenuBackground)); Image title = new Image("title", Assets.mainMenuTitle); title.x = 0; title.y = 340; resetEyeBlink(); stage.addActor(title); dispatcher.registerInputProcessor(stage); settings = game.getSettings(); eyeBlinkImage = new Image("eyeBlink", Assets.eyeBlink); if (settings.getPlayers().isEmpty()) { settings.addPlayer("Player One"); settings.save(game); } setupContinue(); } 

Поэтому единственные возможности, которые я вижу, – это игра, диспетчер и настройки.

Игра устанавливается через этот код в другом классе. Игра является конечной переменной в этом классе:

 game.setScreen(new MainMenuScreen(game)); 

Диспетчер получает установленный в вызове супер выше.

GetSettings () возвращает объект настроек, который устанавливается в самом начале приложения, является закрытым и никогда не отменяется. Его также использовали до этого метода несколько раз.

Нет примитивов для автоматического бокса.

Вот конфигурация proguard:

 -optimizationpasses 5 -dontusemixedcaseclassnames -dontskipnonpubliclibraryclasses -dontpreverify -verbose -optimizations !code/simplification/arithmetic,!field/*,!class/merging/* -keepattributes Signature -keep public class com.alkilabs.hauntedcarnival.settings.Settings -keep public class com.alkilabs.hauntedcarnival.settings.Settings { *; } -keep public class com.alkilabs.hauntedcarnival.settings.Player -keep public class com.alkilabs.hauntedcarnival.settings.Player { *; } -keepnames public class com.alkilabs.hauntedcarnival.world.World -keepnames public class * extends com.alkilabs.hauntedcarnival.world.upgrades.Upgrade -keepnames public class * extends com.alkilabs.hauntedcarnival.world.achievments.Achievement -keepnames public class com.alkilabs.hauntedcarnival.world.monsters.MonsterType -keepclassmembers class * extends com.alkilabs.hauntedcarnival.world.monsters.Monster { public <init>(com.alkilabs.hauntedcarnival.world.monsters.MonsterType, java.lang.Integer, com.alkilabs.hauntedcarnival.world.World); } -keepnames public class com.alkilabs.hauntedcarnival.world.items.ItemType -keepclassmembers class * extends com.alkilabs.hauntedcarnival.world.items.Item { public <init>(com.alkilabs.hauntedcarnival.world.World, java.lang.Integer, java.lang.Integer); } -keep public class * extends android.app.Activity -keep public class * extends android.app.Application -keep public class * extends android.app.Service -keep public class * extends android.content.BroadcastReceiver -keep public class * extends android.content.ContentProvider -keep public class * extends android.app.backup.BackupAgentHelper -keep public class * extends android.preference.Preference -dontwarn com.badlogic.gdx.scenes.scene2d.ui.utils.DesktopClipboard -dontwarn com.badlogic.gdx.utils.JsonWriter -dontwarn com.badlogic.gdx.utils.XmlWriter -keepclasseswithmembernames class * { native <methods>; } -keepclasseswithmembers class * { public <init>(android.content.Context, android.util.AttributeSet); } -keepclasseswithmembers class * { public <init>(android.content.Context, android.util.AttributeSet, int); } -keepclassmembers class * extends android.app.Activity { public void *(android.view.View); } -keepclassmembers enum * { public static **[] values(); public static ** valueOf(java.lang.String); } -keep class * implements android.os.Parcelable { public static final android.os.Parcelable$Creator *; } 

Хорошо, я думаю, что попал в корень проблемы / путаницы.

Одна из вещей, которую выполняет proguard, – это встроенные методы. Из-за этого все содержимое моей функции setupContinue () в нижней части моего конструктора было добавлено непосредственно в содержимое моего конструктора. Итак, теперь у меня есть еще больше кода для обзора, и я вижу некоторые дополнительные возможности для NPE. Я почти уверен, что дойду до конца моей проблемы.

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

Лучше всего использовать файл mapping.txt и инструмент retrace, чтобы найти точное местоположение ошибки. Оттуда было бы легче понять, действительно ли это Proguard или какой-то другой конец, о котором вы не думали.

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

C: \ trace.txt

Теперь в вашем проекте вы найдете папку Proguard с 4 файлами. Предположим, что ваш проект находится в

C: \ проект

Вам нужно будет запустить инструмент retrace (используя пакетный файл для более удобного использования), расположенный в (изменение местоположения вашей папки Android Sdk):

C: \ Android, СДК-окна \ инструменты \ ProGuard \ Bin \ retrace.bat

Перейдите в эту папку и запустите:

Retrace c: \ project \ proguard \ mapping.txt c: \ trace.txt

Оттуда было бы намного проще понять нашу точную строку исключения и, вероятно, найти ошибку.

По моему опыту, единственные вещи, которые могут быть перепутаны, – это сторонние библиотеки. Нормальный код Android для всех моих проектов никогда не пострадал от обфускации.

Извините, что я не могу оставлять комментарии (я новичок в SO).

Это может быть еще одна проблема, с которой я столкнулся. На некоторых телефонах в какой-то момент возникла проблема с отсутствующими библиотеками Android, такими как библиотека JSon.

Я бы порекомендовал вам более внимательно посмотреть, какие телефоны действительно получают NPE – может быть, есть некоторые сходства.

В моем случае это HTC Desire Z, в котором отсутствовала библиотека JSon, и поэтому приложение закрывалось каждый раз, когда вызывалась часть JSon. Проблема была исправлена ​​HTC позже с исправлением для romre Desire Z.

Intereting Posts