背景
閱讀 sunflower 源碼 android/sunflower 時(shí)發(fā)現(xiàn)其使用了 Hilt 組件,其中需要在 MainApplication
上添加 HiltAndroidApp
注解,查看 HiltAndroidApp
源碼,發(fā)現(xiàn)其提供了兩種使用方式:
/**
* Annotation for marking the {@link android.app.Application} class where the Dagger components
* should be generated. Since all components will be built in the same compilation as the annotated
* application, all modules and entry points that should be installed in the component need to be
* transitive compilation dependencies of the annotated application.
*
* <p>Usage of this annotation is similar to {@link dagger.hilt.android.AndroidEntryPoint} with the
* only difference being that it only works on application classes and additionally triggers Dagger
* component generation.
*
* <p>This annotation will generate a base class that the annotated class should extend, either
* directly or via the Hilt Gradle Plugin. This base class will take care of injecting members into
* the Android class as well as handling instantiating the proper Hilt components at the right point
* in the lifecycle. The name of the base class will be "Hilt_<annotated class name>".
*
* <p>Example usage (with the Hilt Gradle Plugin):
*
* <pre><code>
* {@literal @}HiltAndroidApp
* public final class FooApplication extends Application {
* {@literal @}Inject Foo foo;
*
* {@literal @}Override
* public void onCreate() {
* super.onCreate(); // The foo field is injected in super.onCreate()
* }
* }
* </code></pre>
*
* <p>Example usage (without the Hilt Gradle Plugin):
*
* <pre><code>
* {@literal @}HiltAndroidApp(Application.class)
* public final class FooApplication extends Hilt_FooApplication {
* {@literal @}Inject Foo foo;
*
* {@literal @}Override
* public void onCreate() {
* super.onCreate(); // The foo field is injected in super.onCreate()
* }
* }
* </code></pre>
*
* @see AndroidEntryPoint
*/
// Set the retention to RUNTIME because we check it via reflection in the HiltAndroidRule.
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@GeneratesRootInput
public @interface HiltAndroidApp {
/**
* The base class for the generated Hilt application. When applying the Hilt Gradle Plugin this
* value is not necessary and will be inferred from the current superclass.
*/
// TODO(erichang): It would be nice to make this Class<? extends Application> but then the default
// would have to be Application which would make the default actually valid even without the
// plugin. Maybe that is a good thing...but might be better to have users be explicit about the
// base class they want.
Class<?> value() default Void.class;
}
- 一種是使用
Hilt Gradle Plugin
的方式,操作上更簡(jiǎn)單:
@HiltAndroidApp
public final class FooApplication extends Application {
@Inject Foo foo;
@Override
public void onCreate() {
super.onCreate(); // The foo field is injected in super.onCreate()
}
}
- 另一種是不使用
Hilt Gradle Plugin
的方式,需要手動(dòng)給@HiltAndroidApp
設(shè)置 value 值,并且XxxApplication
需繼承成自動(dòng)生成的Hilt_XxxApplication
:
@HiltAndroidApp(Application.class)
public final class FooApplication extends Hilt_FooApplication {
@Inject Foo foo;
@Override
public void onCreate() {
super.onCreate(); // The foo field is injected in super.onCreate()
}
}
問(wèn)題
照葫蘆畫(huà)瓢,使用第一種方式時(shí),一切 OK;使用第二種方式時(shí),無(wú)論怎么操作都報(bào)如下錯(cuò)誤(明明就繼承了 Hilt_MainApplication 的,其實(shí)是 Hilt_MainApplication 沒(méi)有正確生成出來(lái)):
public final class MainApplication {
^
@HiltAndroidApp class expected to extend Hilt_MainApplication. Found: Object
[Hilt] Processing did not complete. See error above for details.
解決
費(fèi)了九牛二虎之力才找到解決問(wèn)題的辦法,在 dagger 官網(wǎng) dagger.dev 有如下描述:
Using Hilt with Kotlin
If using Kotlin, then apply the kapt plugin and declare the compiler dependency using kapt
instead of annotationProcessor
.
Additionally configure kapt to correct error types by setting correctErrorTypes
to true.
dependencies {
implementation 'com.google.dagger:hilt-android:2.41'
kapt 'com.google.dagger:hilt-compiler:2.41'
// For instrumentation tests
androidTestImplementation 'com.google.dagger:hilt-android-testing:2.41'
kaptAndroidTest 'com.google.dagger:hilt-compiler:2.41'
// For local unit tests
testImplementation 'com.google.dagger:hilt-android-testing:2.41'
kaptTest 'com.google.dagger:hilt-compiler:2.41'
}
kapt {
correctErrorTypes true
}
Hilt Gradle plugin
The Hilt Gradle plugin runs a bytecode transformation to make the APIs easier to use. The plugin was created for a better developer experience in the IDE since the generated class can disrupt code completion for methods on the base class. The examples throughout the docs will assume usage of the plugin. To configure the Hilt Gradle plugin first declare the dependency in your project’s root build.gradle
file:
buildscript {
repositories {
// other repositories...
mavenCentral()
}
dependencies {
// other plugins...
classpath 'com.google.dagger:hilt-android-gradle-plugin:2.41'
}
}
then in the build.gradle
of your Android Gradle modules apply the plugin:
apply plugin: 'com.android.application'
apply plugin: 'dagger.hilt.android.plugin'
android {
// ...
}
Warning: The Hilt Gradle plugin sets annotation processor arguments. If you are using other libraries that require annotation processor arguments, make sure you are adding arguments instead of overriding them. See below for an example.
Why use the plugin?
One benefit of the Gradle plugin is that it makes using @AndroidEntryPoint
and @HiltAndroidApp
easier because it avoids the need to reference Hilt’s generated classes.
Without the Gradle plugin, the base class must be specified in the annotation and the annotated class must extend the generated class:
@HiltAndroidApp(MultiDexApplication.class)
public final class MyApplication extends Hilt_MyApplication {}
With the Gradle plugin the annotated class can extend the base class directly:
@HiltAndroidApp
public final class MyApplication extends MultiDexApplication {}
注意:官網(wǎng)不知為什么打不開(kāi),可以直接在 google 搜索框中搜索該網(wǎng)址,然后查看快照即可(后來(lái)通過(guò)修改 C:\Windows\System32\drivers\etc\hosts
文件解決了)。
也就是說(shuō),使用了 kapt 的情況下,需要額外添加如下設(shè)置:
// 使用不帶 Hilt Gradle Plugin 插件的方式需要添加該配置;
// 使用帶 Hilt Gradle Plugin 插件的方式則不需要,估計(jì)插件里默認(rèn)添加了該配置。
kapt {
correctErrorTypes true
}
至此,終于成功編譯過(guò)了。
另外,如果整個(gè)工程是 java 工程,即沒(méi)有使用 koltin 的情況下,自然也不會(huì)用到 kapt,也不需要進(jìn)行上面的配置了。對(duì)應(yīng)的,使用 annotationProcessor 即可。
結(jié)論
總的來(lái)說(shuō),還是推薦使用帶 Hilt Gradle Plugin
的方式,畢竟更簡(jiǎn)單;這里只是糾結(jié)了一下為什么按照其注解里的方式無(wú)法正常編譯成功的原因,最終,問(wèn)題得以解決。