首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Android proguard混淆代码导致了NullPointerException,而实际上它不应该是这样的

Android proguard混淆代码导致了NullPointerException,而实际上它不应该是这样的
EN

Stack Overflow用户
提问于 2011-10-03 03:22:20
回答 3查看 4.9K关注 0票数 6

我在Android Marketplace上发布了一个应用程序。我从一小部分用户(可能2%)那里得到了错误报告,他们使用NullPointerExceptions是没有逻辑意义的。

我自己从来没能复制过这个。代码相对简单,是每个用户都必须遵循的通用代码路径。实际上,我已经将可能创建NPE的每一行代码都封装在一个try-catch块中,并抛出了一个自定义的运行时异常,但我仍然没有捕获到NullPointerException错误。

在这一点上,我能想到的唯一的事情就是与我的Proguard混淆有关的东西。我看过其他一些文章,讨论如果您注意到奇怪的行为,就去掉-overloadaggressively选项,但据我所知,我没有使用该选项。

还有没有人经历过使用android和proguard的神秘NPE?人们是否可以推荐其他设置来降低可能导致此问题的优化?

还有其他想法吗?

作为参考,下面是获取NPE的非模糊函数:

代码语言:javascript
复制
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是另一个类中的最后一个变量:

代码语言:javascript
复制
game.setScreen(new MainMenuScreen(game));

dispatcher在上面的调用中进行了设置。

getSettings()返回一个在应用程序启动时设置的设置对象,它是私有的,永远不会被取消设置。在此方法之前,它也使用了几次。

没有自动装箱的原语。

下面是proguard的配置:

代码语言:javascript
复制
-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 *;
}
EN

回答 3

Stack Overflow用户

发布于 2011-10-05 01:24:55

好了,我想我找到了问题/困惑的根源。

proguard做的一件事就是内联一些方法。因此,我的构造函数底部的setupContinue()函数的全部内容都被直接添加到我的构造函数的内容中。所以现在我有更多的代码要检查,我确实看到了NPE的更多可能性。我很确定我会查个水落石出。

我通过获取proguard生成的obfuscated.jar,并通过反编译器运行它来解决这个问题。这是一个有趣的练习,因为你对proguard的内部工作原理几乎没有更多的了解。我强烈推荐那些想要更好地理解proguard对他们代码的影响的人。

票数 8
EN

Stack Overflow用户

发布于 2011-10-03 03:46:23

最好的办法是使用mapping.txt文件和回溯工具来找到错误的确切位置。从那里,它将更容易理解,如果它确实是Proguard或其他一些你没有想到的最终案例。

为此,您需要将堆栈跟踪从开发人员控制台复制到另一个文件,假设它的名称为

c:\trace.txt

现在,在你的项目中,你会发现一个包含4个文件的Proguard文件夹。让我们假设您的项目在

项目c:\

您需要做的是运行位于(更改到Android Sdk文件夹的位置)的retrace工具(使用批处理文件以便于使用):

c:\android-sdk-windows\tools\proguard\bin\retrace.bat

转到该文件夹并运行:

回溯c:\project\proguard\mapping.txt c:\trace.txt

从那时起,我们将更容易计算出异常的确切行,并可能找到错误。

根据我的经验,唯一可能搞砸的是第三方库。对于我所有的项目来说,普通的Android代码从来没有因为混淆而受到伤害。

票数 2
EN

Stack Overflow用户

发布于 2011-10-03 06:06:21

抱歉,我还不能发表评论(我是新手)。

这可能是我自己遇到的另一个问题。在一些手机上,缺少安卓类库,比如JSon类库,在某些时候会出现问题。

我建议你仔细看看哪些手机真正获得了NPE --可能有一些相似之处。

在我的例子中,它是HTC Desire Z,缺少JSon库,所以每次调用JSon部件时,应用程序强制关闭。这个问题后来被HTC修复,对Desire的rom进行了热修复。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7628638

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档