Anvil Utils: Effortless assisted injection in multi-module Android projects
Hey there, fellow Android developers! 👋 Are you tired of the hassle that comes with managing assisted injection in your modular app? Well, buckle up because I’ve got some exciting news for you! 🚀
Introducing Anvil Utils - a game-changing library that will make your life easier when working with Dagger and Anvil in multi-module projects.
The Struggle is Real
Picture this: you have a beautifully architected modular app with api
and implementation
modules per feature. Everything is going smoothly until you encounter a situation where your feature contains a factory for an entity and want to expose it in an api
, and you need to make this factory available within the Dagger graph. 😰
Let’s walk through the ways to do that.
Bare Dagger approach
For instance, you have such public API for your feature module:
interface MyClass {
interface Factory {
fun create(param1: String, param2: Int): MyClass
}
}
Traditionally, you’d have to manually create an @AssistedFactory
in the implementation module, inherit from the public interface in the API module, and write a Dagger module which binds assisted factory to it’s public interface. Also, you would need to maintain both factory interfaces - public one and implementation one. Here’s an example:
class DefaultMyClass @AssistedInject constructor(
@Assisted param1: String,
@Assisted param2: Int
) : MyClass {
@AssistedFactory
interface Factory: MyClass.Factory {
override fun create(param1: String, param2: Int): DefaultMyClass
}
}
@Module
interface MyClassFactoryBindingModule {
@Binds
fun bindFactory(impl: DefaultMyClass.Factory): MyClass.Factory
}
Seems like a lot of work, doesn’t it?
Let’s make it easier to maintain step by step
Introducing Anvil
Anvil is a Kotlin compiler plugin which helps to drastically reduce the boilerplate needed to use Dagger 2 in your application. Also, if properly configured, it can improve build times in your application by removing the requirement to run Dagger 2 annotation processor in your feature modules. I will not dive deep into what Anvil is and why you should consider using it. That’s a topic for another day. Please read through the Anvil readme here to get what it is about. https://github.com/square/anvil
Thanks to Anvil, you can get rid of the binding module using @ContributesBinding
:
class DefaultMyClass @AssistedInject constructor(
@Assisted param1: String,
@Assisted param2: Int
) : MyClass {
@ContributesBinding(AppGraph::class, MyClass.Factory::class)
@AssistedFactory
interface Factory: MyClass.Factory {
override fun create(param1: String, param2: Int): DefaultMyClass
}
}
Anvil will generate corresponding module which will bind DefaultMyClass.Factory
to MyClass.Factory
for you.
This lowers the amount of boilerplate, but it’s still there!
You have to manually keep public factory interface and implementation interface aligned with the constructor!
Can we go further and reduce the amount of work needed to support this use case?
Sure!
@ContributesAssistedFactory to the Rescue!
Fear not, my friend! With Anvil Utils, you can say goodbye to the manual labor of creating assisted factories. The @ContributesAssistedFactory
annotation is here to save the day! 🦸♂️
This powerful annotation automatically generates assisted factories for your annotated classes and contributes them to the specified scope as bindings of the provided factory type. It’s like having a personal assistant that takes care of all the heavy lifting for you!
You now can remove the @AssistedFactory
interface completely and annotate the DefaultMyClass
with @ContributesAssistedFactory
:
@ContributesAssistedFactory(AppGraph::class, MyClass.Factory::class)
class DefaultMyClass @AssistedInject constructor(
@Assisted param1: String,
@Assisted param2: Int
) : MyClass
And voila! Anvil Utils will generate the necessary assisted factory for you, without breaking a sweat. 😎
In the wild example
To demonstrate the power of this library I’ve made a huge pull request to beautiful open-source project - companion app for the Flipper - Tamagochi for hackers. Please, take a look if you’re interested: https://github.com/flipperdevices/Flipper-Android-App/pull/798
Embrace the Power of Anvil Utils
So, what are you waiting for? Give Anvil Utils a try in your next modular Android project and experience the joy of hassle-free assisted injection. Your codebase will thank you, and your fellow developers will be in awe of your newfound superpowers! 💪
Happy coding, and may the power of Anvil Utils be with you! 🚀
P.S. Don’t hesitate to open feature requests - I’m eager to improve the library and add more features.