简体   繁体   中英

Running signed android app, NPE occurs, possibly due to proguard?

I have an android app I have been developing, and it's now ready to launch. It works great running from eclipse unsigned. When I export a signed copy and run it, an NPE occurs. I've tried creating the signed version with the latest supplied proguard files (proguard-android.txt and proguard-android-optimize.txt). No difference with either. The only mods I've made via my local proguard config file is to leave line numbers so I can get a decent stack trace.

The NPE is what has me scratching my head. I use a lock object for synchronization, and I initialize it in the definition of the object and also during stream initialization:

public class HttpRequest extends NetworkRequest {
  private transient Object lock = new Object();
<snip>
private void readObject(java.io.ObjectInputStream in)
  throws IOException, ClassNotFoundException {
  in.defaultReadObject();
  lock = new Object();
}

In my debugging version, lock is never null, but in my signed version, when I go to use the lock object, it's null, consistently. I can only assume proguard is doing something I don't want, but this is the first time I've delved into proguard so I'm a bit out of my element.

Can anyone suggest how I can debug this further?

Proguard does three things: shrink, optimize, obfuscate.

In the shrink step, it cuts out any unused program code. What may be happening to you is that Proguard may be stripping away the readObject method because it appears to be unused. I would expect there to be a keep-rule for that method out of the box, but apparently there isn't, or at least not in the Android SDK.

One way to verify that would be to assemble your app with -dontobfuscate in the proguard config, then extracting the classes.dex file from the APK package and running dexdump classes.dex and looking for the presence or absence of the readObject method.

Ultimately, to ensure the readObject method is preserved, you would add the following rule to your ProGuard config:

-keepclassmembers class * implements java.io.Serializable {
  private void readObject(java.io.ObjectInputStream);
}

Updated by mvsjes2 to add the config that actually worked for me:

-keepnames class * implements java.io.Serializable

-keepclassmembers class * implements java.io.Serializable {
    static final long serialVersionUID;
    private static final java.io.ObjectStreamField[] serialPersistentFields;
    !static !transient <fields>;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace();
    java.lang.Object readResolve();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM