簡體   English   中英

Android proguard混淆代碼導致NullPointerException,當它真的不應該

[英]Android proguard obfuscated code is causing NullPointerException when it really shouldn't be

我已在Android Marketplace上分發了一個應用程序。 我從一小部分用戶(可能是2%)收到錯誤報告,他們在那里得到NullPointerExceptions,這在邏輯上沒有意義。

我自己從來沒有能夠復制過這個。 代碼相對簡單,是每個用戶必須遵循的通用代碼路徑。 我實際上已經采用了可能創建NPE並將其包裝在try-catch塊中並拋出自定義運行時異常的每個單獨的代碼行,但我仍然得到未捕獲的NullPointerException錯誤。

在這一點上,我唯一能想到的就是與我的Proguard混淆相關的東西。 我看過其他一些文章談到如果你注意到奇怪的行為而取出-overloadaggressively選項,但據我所知,我沒有使用該選項。

有沒有其他人使用android和proguard經歷過神秘的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的更多可能性。 我很確定我會找到問題的根源。

我通過獲取proguard產生的obfuscated.jar並通過反編譯器運行它來解決這個問題。 這是一個有趣的練習,因為你可以更深入地了解proguard的內部工作原理。 我強烈建議那些想要更好地理解proguard對其代碼的影響的人。

您最好的選擇是使用mapping.txt文件和回溯工具來查找錯誤的確切位置。 從那里可以更容易理解它是否確實是Proguard或其他一些您沒有想到的最終案例。

要做到這一點,您需要將堆棧跟蹤從開發人員的控制台復制到另一個文件,讓我們假設它被調用

C:\\ trace.txt

現在,在您的項目中,您將找到包含4個文件的Proguard文件夾。 我們假設你的項目在

C:\\項目

您需要做的是運行位於(更改為Android Sdk文件夾位置)的回溯工具(使用批處理文件以便於使用):

C:\\ Android的SDK-WINDOWS \\工具\\ proguard的\\ BIN \\ retrace.bat

轉到該文件夾​​並運行:

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

從那以后,可以更容易地確定異常的確切行並可能找到錯誤。

根據我的經驗,唯一可能搞得搞亂的是第三方庫。 對於我的所有項目,普通的Android代碼從未因混淆而受到損害。

對不起,我還不能發表評論(我是SO的新手)。

這可能是我自己遇到的另一個問題。 在某些手機上,在某些方面存在一個問題,即缺少像JSon庫這樣的Android庫。

我建議你仔細看看實際獲得NPE的手機 - 可能會有一些相似之處。

在我的情況下,它是HTC Desire Z,它缺少JSon庫,所以每次調用JSon部件時app力都會關閉。 HTC稍后使用針對Desire Z的rom的修補程序解決了這個問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM