He distribuido una aplicación en Android Marketplace. Recibo informes de error de un pequeño grupo de usuarios (quizás un 2%) donde obtienen NullPointerExceptions donde no tiene sentido lógico.El código ofuscado de Android Proguard causa NullPointerException cuando realmente no debería ser
Nunca he podido replicar esto yo mismo. El código es relativamente sencillo y es una ruta de código común que CADA usuario debe seguir. De hecho, tomé cada línea de código por separado que podría estar creando el NPE y lo envolví en un bloque try-catch y lancé una excepción de tiempo de ejecución personalizada, pero todavía estoy obteniendo errores de NullPointerException no detectados.
En este punto, lo único que puedo imaginar es algo relacionado con mi ofuscación de Proguard. He visto algún otro artículo hablando acerca de tomar la opción -overloadaggressively si notas un comportamiento extraño, pero hasta donde sé, no estoy usando esa opción.
¿Alguien más ha experimentado misteriosos NPE usando android y proguard? ¿Hay alguna otra configuración que las personas puedan recomendar para reducir las optimizaciones que podrían estar causando este problema?
¿Alguna otra idea?
Para referencia, aquí es la función unobfuscated que está recibiendo la 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();
}
lo que la única posibilidad que puedo ver son juego, despachador y los ajustes.
juego se establece a través de este código en otra clase. juego es una variable final en esa otra clase:
game.setScreen(new MainMenuScreen(game));
despachador se establece dentro de la llamada a super arriba.
getSettings() devuelve un objeto de configuración que se establece desde el inicio de la aplicación, es privado y nunca se desarma. También se usa antes de este método varias veces.
No hay primitivas de auto-boxing.
aquí es la configuración 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 *;
}
¿Pueden por favor publicar el código que causa la configuración de NPE y ProGuard que usó? – Idolon
Agregué más detalles sobre el código específico y mi configuración proguard – Paul