问题
I'm struggling with the setup of Dagger (1.0.1), in a existing application. It was configured to use ProGuard but I disabled it for this test with -dontobfuscate
.
When I enable dagger-compiler it's able to successfully generate a dot file with the dependencies graph, but when I remove the compiler and build the app in Release mode it crashes during startup, complaining that it's unable to create the object graph.
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
I see MyAppBaseActivity
and it's dependencies with CroutonManager
or ConnectionMonitor
being displayed in the generated dot file, so according to this comment I expected this to work. AFAIK if there was something wrong it should be detected by the compiler-enabled build that I used to generate the dot file.
UPDATE:
I previously stated that
In Debug mode it never fails
but it's not really true after further testing: In Debug mode it doesn't fail because ProGuard is disabled, whereas in Release mode it is enabled by default. If I build the app in Release mode but skip ProGuard, I don't get the errors either and the app successfully starts. So the problem is definitely related to my ProGuard configuration.
回答1:
Dagger relies a lot on reflection and class names that are hard-coded and manipulated as strings. This makes the code difficult to shrink/optimize/obfuscate.
The following configuration works for the sample dagger/examples/simple in Dagger 1.1.0:
-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
The configuration keeps all fields and methods with javax.inject
or dagger
annotations, and all parameterless constructors. ProGuard might otherwise remove them if they appear unused, but Dagger is actually injecting/accessing them through reflection. This is similar to RoboGuice.
It also has to keep all adapter classes generated by Dagger.
It also has to keep all class names related to these adapter classes, so the names still match. In this sample, those are almost all classes in the package coffee
, so the easiest way is to use a wild-card. This line will be different for other applications.
Finally, it also has to keep the name of the class dagger.Lazy
, since its name is hard-coded as a string in the generated code.
回答2:
I got the app to start after adding -dontshrink
to the ProGuard config file. Having -dontobfuscate
at the beginning was not enough.
In fact, if I remove -dontobfuscate
it also works.
I definitely need finer control for this but it's a starting point. My current ProGuard setup for Dagger is:
#############
# Dagger #
#############
-keep class dagger.** { *; }
-dontwarn dagger.internal.codegen.**
回答3:
Dagger doesn't require @Inject
to be on a class to be passed into graph.inject(myActivity)
because some activities may not have any injections to make. However, these seem like upstream dependencies, which means that they need to be provided to ComponentInfo
, and therefore need to be provisioned by Dagger. It cannot do this if it cannot create these classes, and it can't do so if these are not annotated, unless it provides them via a @Provides
method.
So, you either need to create an @Module
-annotated class which returns these types from @Provides
-annotated methods, or you need to add @Inject
to their constructor.
-keep class * extends dagger.internal.Binding
That said, in this case, are you using proguard in "release" mode? And not proguarding in debug mode? If so, I suspect Proguard to be stripping away annotations. You'll need to do some variant of:
-keep class javax.inject.** { *; }
... to ensure that Proguard doesn't remove the annotations.
回答4:
I ended up burning a week+ trying to get this to work. In the end I failed and decided to give DexGuard a shot. It worked beautifully right out of the box. Yes its a commercial product but DexGuard has great support and because of such we were able to finally ship. Id definitely recommend DexGuard if you absolutely need to solve this issue.
来源:https://stackoverflow.com/questions/18102084/dagger-cannot-create-object-graph-although-it-can-produce-dot-file