Dagger + Proguard obfuscation, Errors creating obj

2019-01-26 18:56发布

Running an obfuscated version of my application throws the following stacktrace

java.lang.RuntimeException: Unable to create service com.mycompany.myapp.async.alarms.AlarmIntentService: java.lang.IllegalStateException: Errors creating object graph:
    dagger.Lazy could not be bound with key dagger.Lazy required by dagger.Lazy  com.mycompany.scheduler.c.mNotificationDisplayer

If I add -dontobfuscate, it runs smoothly

Here's the class that contains that field

public abstract class AbstractAlarmSchedulerService extends IntentService {

  @Inject
  Lazy<AbstractAlarmSchedulerNotificationDisplayer> mNotificationDisplayer;

I extend from this class in my application, but it belongs to an external library.

These are my dagger proguard rules, copied from https://stackoverflow.com/a/18177491/218473

#Dagger
-keepattributes *Annotation*

-keepclassmembers,allowobfuscation class * {
    @javax.inject.* *;
    @dagger.* *;
    <init>();
}

-keep class * extends dagger.internal.Binding
-keep class * extends dagger.internal.ModuleAdapter

-keep class **$$ModuleAdapter
-keep class **$$InjectAdapter
-keep class **$$StaticInjection

-keep class dagger.* { *; }

-keep class javax.inject.* { *; }
-keep class * extends dagger.internal.Binding
-keep class * extends dagger.internal.ModuleAdapter
-keep class * extends dagger.internal.StaticInjection

-keep !abstract class com.mycompany.** { *; }

-keepnames class dagger.Lazy

I've tried keeping all classes and all members to see if that fixed anything, but the error persisted

-keep class * { *; }

com.mycompany.scheduler is an external library, while com.mycompany.myapp contains the source for the actual application.

In case it's needed, here's the Module I'm using

@Module(injects = {AlarmIntentService.class, ReminderNotificationDisplayer.class, AlarmsBroadcastReceiver.class})
public class AndroidModule {
  private final AbstractMyApplication application;

  public AndroidModule(AbstractMyApplication application) {
    this.application = application;
  }

  /**
   * Allow the application context to be injected
   */
  @Provides @Singleton
  Context provideApplicationContext() {
    return application;
  }

  @Provides
  public AlarmManager provideAlarmManager(Context context){
    return (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
  }

  @Provides
  @Singleton
  public NotificationManager provideNotificationManager(Context context){
    return (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
  }

  @Provides
  @Singleton
  public AbstractAlarmSchedulerNotificationDisplayer provideNotificationDisplayer() {
    return new ReminderNotificationDisplayer();
  }
}

I'm using dagger & dagger-compiler 1.2.+ dependencies

Thanks!

2条回答
Emotional °昔
2楼-- · 2019-01-26 19:24

I wasn't able to get Dagger 1.2 to work with ProGuard, and reading issue on Progruard github account I think I'm not alone - https://github.com/square/dagger/issues/202

However, I've managed to get version 1.0.0 to work (without dagger-compiler!) with rules you mentioned above. Works fine in large Android apps, despite being quite old.

查看更多
孤傲高冷的网名
3楼-- · 2019-01-26 19:47

Dagger 1.x has issues with obfuscation. It can do code-shrinking with appropriate -keep statements, but obfuscation becomes problematic because of the use of String keys. The Strings are generated prior to proguarding, but consumed after proguarding, and do not line up with the newly-renamed types.

Dagger 1.x (around 1.0.0) before we disabled reflective module adapters will work, as pure-reflection results in both provision and injection of a type to be considered "just in time" (i.e. after proguarding) so obfuscated types match up. If code-obfuscation is a higher priority than performance, do consider using this slightly older version.

Dagger 2.x (in progress) is free of string keys, and results in direct class references, and should play very nicely with Proguard. Stay tuned to the dagger lists and project. We expect early versions of 2.x to drop within weeks of this posting.

Also, and more specifically, make sure you -keepattributes Signature. The specific error you are seeing is because JDK5+ generics are being stripped by proguard. One never injects Lazy, one injects Lazy<Foo>. That will fix this specific error, though you will then have the problem mentioned above.

查看更多
登录 后发表回答