2011-10-02 3 views
6

Android 마켓에서 애플리케이션을 배포했습니다. 논리적으로 이해가되지 않는 곳에서 NullPointerExceptions을 얻고있는 소수의 사용자 (아마도 2 %)에게서 오류 보고서가 다시 전송됩니다.Android proguard 난독 화 코드로 인해서는 안되는 NullPointerException이 발생합니다.

본인 스스로 복제 할 수 없었습니다. 코드는 비교적 간단하며 모든 사용자가 따라야하는 공통 코드 경로입니다. 사실 NPE를 만들 수있는 모든 코드 라인을 가져 와서 try-catch 블록에 래핑하고 사용자 정의 런타임 예외를 throw하지만 여전히 잡히지 않은 NullPointerException 오류가 발생합니다.

내가 생각할 수있는 유일한 점은 내 Proguard 난독 화와 관련된 것입니다. 당신이 이상한 행동을 느낀다면 overovergressive 옵션을 꺼내는 것에 대해 이야기하는 다른 기사를 보았습니다. 그러나 말할 수있는 한, 나는 그 옵션을 사용하지 않고 있습니다.

안드로이드와 프로 가드를 사용하여 신비한 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(); 


} 

그래서 유일한 가능성 나는 게임, 디스패처 및 설정입니다 볼 수 있습니다 참고로

, 여기에 읽을 수있게 NPE을 받고있다 기능입니다.

게임은이 코드를 통해 다른 클래스에 설정됩니다. 게임은 다른 클래스의 최종 변수입니다.

game.setScreen(new MainMenuScreen(game)); 

dispatcher가 위의 super 호출에서 설정됩니다.

getSettings()는 응용 프로그램의 맨 처음에 설정되고 비공개이며 결코 설정이 해제되지 않는 설정 객체를 반환합니다. 이 방법 이전에도 여러 번 사용되었습니다.

자동 권투 기본 요소가 없습니다.

-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 *; 
} 
+0

NPE 및 ProGuard 설정이 사용 된 코드를 게시 할 수 있습니까? – Idolon

+0

특정 코드와 proguard 구성에 대한 세부 정보를 추가했습니다. – Paul

답변

2

가장 좋은 방법은 오류의 정확한 위치를 찾기 위해 mapping.txt 파일과 트레이스 도구를 사용하는 것입니다 : 여기

는 난독의 설정입니다. 실제로 Proguard 또는 생각하지 않은 다른 최종 사례인지 쉽게 이해할 수 있습니다. \ trace.txt

지금, 당신의 프로젝트 :

이 작업을 수행하려면 다른 파일에 개발자 콘솔에서 스택 추적을 복사해야합니다, C의 그것

을라고 가정하자 4 개의 파일이있는 Proguard 폴더를 찾을 수 있습니다. 의 프로젝트가 가정하자에

C : \ 프로젝트

당신은에 (변화에 위치한 (쉽게 사용할 수 있도록 배치 파일을 사용하여) 트레이스 도구를 실행해야 할 것들 안드로이드 SDK 폴더의 위치) :

C : \ 안드로이드-SDK-WINDOWS \ 도구 \ 난독 \ 빈 \의 retrace.bat

해당 폴더로 이동하여 실행

귀선 C : \ 프로젝트 \의 난독 \ mapping.txt C : \ trace.txt

이부터, 우리의 정확한을 파악하는 것이 훨씬 쉬울 것 오류의 라인을 찾을 수 있습니다.

제 경험상 엉망으로 만들 수있는 유일한 사항은 타사 라이브러리입니다. 내 모든 프로젝트에 대한 일반적인 Android 코드는 난독 화에서 결코 해를 입지 않았습니다.

+0

예 이미 완료했습니다. 정확한 메서드와 그 메서드를 호출 한 전체 스택 추적을 알고 있습니다. 내가 모르는 유일한 것은 줄 번호이지만 이것은 줄 번호가없는 프로덕션 릴리스이기 때문입니다. 또한 Proguard는 최적화 단계에서 코드의 일부를 다시 작성합니다 (Proguard가 의심되는 이유 중 하나). 그래서 저는 NPE를 생산할 수있는 각 라인의 구식 패션 디버깅으로 전락했지만 아아, 주사위는 없었습니다. – Paul

+0

그래서 내가 당신을 위해 가지고있는 조언은 며칠 동안 난독성없는 버전을 올려 놓고 추가 오류 보고서가 있는지 확인하는 것입니다 ...Proguard에서 가장 복잡한 애플 리케이션에서부터 가장 간단한 애플 리케이션에 이르기까지 필자의 코드에서 오류가 발생하지 않았으며 항상 프로젝트를 난처하게 만들었습니다. – IncrediApp

+0

그래, 나는 그것에 와야 할지도 모른다고 걱정했지만 불행히도 나는 모든 사람이 볼 수 있도록 내 코드를 야생으로 내 보내지 않을 것입니다. 휴대 전화에서 프로 가드 코드 문제에 대한 다른 게시물을 보았습니다. http://stackoverflow.com/questions/93290/best-java-obfuscation-application-for-size-reduction 그렇다면 전례가없는 것 같습니다. . 나는 다른 사람들이 비슷한 상황을 겪었기를 바랄 뿐이었다. – Paul

1

죄송합니다. 아직 댓글을 올릴 수 없습니다 (전).

이것은 나 자신과 마주 칠 수있는 또 다른 문제 일 수 있습니다. 일부 휴대 전화에서는 JSon 라이브러리와 같은 Android 라이브러리가 누락 된 문제가있었습니다.

실제로 NPE를 얻는 전화기를 자세히 살펴 보는 것이 좋습니다. 몇 가지 유사점이있을 수 있습니다.

필자의 경우 HTC Desire Z가 JSon 라이브러리가 없어서 JSon 파트가 호출 될 때마다 앱 강제 종료가 발생했습니다. 문제는 나중에 Desire Z의 ROM에 대한 핫픽스로 HTC에서 수정되었습니다.

8

좋아요, 문제의 근본 원인/혼란이라고 생각합니다.

proguard가하는 일 중 하나는 인라인 방식입니다. 이 때문에 내 생성자 맨 아래에있는 내 setupContinue() 함수의 전체 내용이 내 생성자의 내용에 직접 추가되었습니다. 이제 검토 할 코드가 더 많아졌고 NPE에 대한 가능성이 더 많습니다. 나는 내 문제의 맨 아래로 갈 것이라고 확신한다.

나는 이것을 알아 내기 위해 proguard가 생성 한 obfuscated.jar를 가져 와서 decompiler를 통해 실행했습니다. Proguard의 내부 동작에 대해 더 많은 통찰력을 얻으면서 흥미로운 연습을합니다. Proguard가 코드에 미치는 영향을 더 잘 이해하고자하는 사람들에게이 기능을 적극 권장합니다.

+0

처리 된 코드를 보면 매우 유용 할 수 있습니다. ProGuard (현재 4.6 또는 4.7 베타)의 최신 버전을 사용하고 있는지 확인해야합니다. 특히 버전 4.6에는 메서드를 이동 (인라인 됨)되어 실행되지 않는 정적 초기화 프로그램과 관련된 수정 사항이 포함되어 있습니다. 여전히 문제가 일관되게 발생하지 않는다는 것은 놀라운 일입니다. –

+0

Proguard in-lining 코드에 관한 부분은 큰 도움이되었습니다. 이제 사용자가 제출 한 크래시/스택 추적이 NPE를 초래하는 실제 코드 줄 대신 메서드 서명에서 끝나는 것처럼 보이는 이유를 알았습니다. 문제를 일으키는 라인을 특별히 지적하지 않는 것이 너무 나쁩니다. 메소드가 코드 스택을 포함하고 있다면 (건초 더미에서 바늘을 찾는 것과 같이) 정말 짜증이납니다. –