Dagger + Proguard混淆,创建对象图时出现错误

4
运行我的应用程序的混淆版本会抛出以下堆栈跟踪。
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

如果我添加-dontobfuscate,它就可以顺利运行。

这是包含该字段的类。

public abstract class AbstractAlarmSchedulerService extends IntentService {

  @Inject
  Lazy<AbstractAlarmSchedulerNotificationDisplayer> mNotificationDisplayer;

我在应用程序中扩展了这个类,但它属于外部库。

以下是我的Dagger ProGuard规则,复制自https://dev59.com/3HXYa4cB1Zd3GeqP5mSz#18177491

#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

我尝试保留所有类和成员,以查看是否修复了任何错误,但错误仍然存在。

-keep class * { *; }

com.mycompany.scheduler是一个外部库,而com.mycompany.myapp包含实际应用程序的源代码。

如果需要的话,这是我正在使用的模块。

@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();
  }
}

我正在使用dagger和dagger-compiler 1.2.+的依赖项。
谢谢!
2个回答

9
Dagger 1.x在混淆方面存在问题。它可以通过适当的-keep语句来进行代码缩小,但由于使用了字符串键,混淆变得棘手。这些字符串在proguarding之前生成,但在proguarding后被使用,并且与新命名的类型不匹配。
Dagger 1.x(大约在1.0.0左右)在我们禁用反射模块适配器之前将工作,因为纯反射会导致类型的提供和注入被认为是“即时的”(即在proguarding之后),因此混淆的类型会匹配。如果代码混淆比性能更重要,请考虑使用这个稍旧的版本。
Dagger 2.x(正在进行中)不需要字符串键,产生直接的类引用,并且应该与Proguard非常相容。请关注dagger列表和项目。我们期待2.x的早期版本在发布后几周内推出。
此外,请确保使用-keepattributes Signature。你看到的具体错误是因为proguard剥离了JDK5+泛型。一个永远不会注入 Lazy ,只会注入Lazy<Foo>。这将修复此特定错误,但然后你将面临上述问题。

感谢您的详细回答,也非常感谢您提供的库! - Maragues

1
我无法让Dagger 1.2与ProGuard一起工作,并且在阅读Proguard github帐户上的问题时,我认为我并不孤单-https://github.com/square/dagger/issues/202 然而,我已经成功地让版本1.0.0(没有dagger-compiler!)与您上面提到的规则一起工作。尽管它非常老旧,但在大型Android应用程序中运行良好。

根据我所了解的,Dagger-Compiler会从运行时中删除反射以提高性能,特别是在旧版Android上。不管怎样,感谢您的回答。 - Maragues
1
我认为1.0.1也应该可以工作,但1.1.0使用了dagger-compiler,这将导致它无法工作。 - EpicPandaForce

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接