5

我正在努力在现有应用程序中设置 Dagger (1.0.1)。它被配置为使用 ProGuard,但我为这个测试禁用了它-dontobfuscate

当我启用 dagger-compiler 时,它能够成功地生成一个带有依赖关系图的点文件,但是当我删除编译器并在发布模式下构建应用程序时,它在启动过程中崩溃,抱怨它无法创建对象图。

java.lang.RuntimeException: Unable to start activity 
  ComponentInfo{com.corp.myapp/com.corp.myapp.ui.activity.MainActivity}: 
  java.lang.IllegalStateException: Errors creating object graph:

No injectable members on com.corp.myapp.core.services.ConnectionMonitor. Do 
  you want to add an injectable constructor? required by 
  com.corp.myapp.core.services.ConnectionMonitor 
  com.corp.myapp.ui.activity.MyAppBaseActivity.connectionManager

No injectable members on com.corp.myapp.ui.crouton.CroutonManager. Do you want 
  to add an injectable constructor? required by 
  com.corp.myapp.ui.crouton.CroutonManager 
  com.corp.myapp.ui.activity.MyAppBaseActivity.croutonManager

No injectable members on com.corp.core.assembler.ResourceAssembler. Do you want 
  to add an injectable constructor? required by 
  com.corp.core.assembler.ResourceAssembler 
  com.corp.myapp.ui.activity.MyAppBaseActivity.resourceAssembler

我看到MyAppBaseActivity它与生成的点文件的依赖关系CroutonManagerConnectionMonitor显示在生成的点文件中,所以根据这个评论,我希望这可以工作。AFAIK 如果有问题,应该由我用来生成点文件的启用编译器的构建检测到。


更新:

我之前说过

在调试模式下它永远不会失败

但经过进一步测试后并非如此:在调试模式下它不会失败,因为 ProGuard 被禁用,而在发布模式下它默认启用。如果我在 Release 模式下构建应用程序但跳过 ProGuard,我也不会收到错误并且应用程序成功启动。所以这个问题肯定和我的 ProGuard 配置有关。

4

4 回答 4

17

Dagger 在很大程度上依赖于反射和类名,它们被硬编码并作为字符串操作。这使得代码难以收缩/优化/混淆。

以下配置适用于 Dagger 1.1.0 中的示例 dagger/examples/simple

-keepattributes *Annotation*

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

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

-keepnames !abstract class coffee.*

-keepnames class dagger.Lazy

配置保留所有带有javax.injectdagger注释的字段和方法,以及所有无参数的构造函数。如果它们看起来未使用,ProGuard 可能会以其他方式删除它们,但 Dagger 实际上是通过反射注入/访问它们。这类似于 RoboGuice。

它还必须保留 Dagger 生成的所有适配器类。

它还必须保留与这些适配器类相关的所有类名,因此名称仍然匹配。在这个示例中,这些几乎都是 package 中的所有类coffee,因此最简单的方法是使用通配符。这条线对于其他应用程序会有所不同。

最后,它还必须保留类的名称dagger.Lazy,因为它的名称在生成的代码中被硬编码为字符串。

于 2013-08-11T22:49:46.123 回答
1

Dagger 不需要@Inject在要传递的类上,graph.inject(myActivity)因为某些活动可能不需要进行任何注入。但是,这些看起来像是上游依赖项,这意味着它们需要提供给ComponentInfo,因此需要由 Dagger 提供。如果它不能创建这些类,它就不能这样做,如果它们没有注释,它就不能这样做,除非它通过@Provides方法提供它们。

所以,你要么需要创建一个@Module-annotated 类,它从 -annotated 方法返回这些类型@Provides,要么你需要添加@Inject到它们的构造函数中。

-keep class * extends dagger.internal.Binding

也就是说,在这种情况下,您是否在“发布”模式下使用 proguard?而不是在调试模式下进行保护?如果是这样,我怀疑 Proguard 正在剥离注释。你需要做一些变体:

-keep class javax.inject.** { *; }

...以确保 Proguard 不会删除注释。

于 2013-08-07T13:58:25.930 回答
1

添加-dontshrink到 ProGuard 配置文件后,我启动了应用程序。一开始有-dontobfuscate是不够的。

事实上,如果我删除-dontobfuscate它也可以。

我肯定需要对此进行更好的控制,但这是一个起点。我当前对 Dagger 的 ProGuard 设置是:

#############
#   Dagger  #
#############

-keep class dagger.** { *; }
-dontwarn dagger.internal.codegen.**
于 2013-08-07T17:21:13.587 回答
0

我最终烧了一个星期+试图让它工作。最后我失败了,决定给 DexGuard 一个机会。它开箱即用,效果很好。是的,它是一种商业产品,但 DexGuard 有很大的支持,因此我们最终能够发货。如果你绝对需要解决这个问题,我绝对推荐 DexGuard。

于 2014-01-22T15:29:12.503 回答