mustafaberkaymutlu / uv-index

This is a work-in-progress (🔧️) ultraviolet index viewer app for demonstrating Instant Apps + Kotlin + Dagger + MVP
Apache License 2.0
67 stars 9 forks source link

multiple <android:name=""> for instant app #1

Open doanappdev opened 6 years ago

doanappdev commented 6 years ago

Hi I have been looking at how you have structured you instant app for dagger2.

I have a question about using dagger2 for multiple features, in your example you have a feature module called 'query'. In the manifest file for that feature you have the following: android:name=".QueryApplication" in tag.

What happens if you have another feature module, is it possible to add dagger2 to the new feature module?

When I try setting "android:name=.SecondFeatureModule" in the new feature module manifest file, I get a compilation error saying AndroidManifest.xml file cannot have duplicate attributes i.e 'android:name=' is being added twice

Do you have any suggestions for resolving this? Or does your example only work if you have 1 feature module for instant app? Would you need to setup dagger2 differently if you had multiple feature modules?

mustafaberkaymutlu commented 6 years ago

Yes, this is an issue with this project right now. I have been trying to solve this, here are my findings.

Dagger 2 can work with multi-feature modules without any problem with this setup.

The problem is having different application classes in each feature module causes a conflict in app and instantapp modules.

Application classes work fine on their own (in instant-app mode there is only one application class per module/app). But we have to choose one application class for both app and instantapp module (because first and second feature's application classes will cause a conflict).

We can not choose some feature's application class for app module because we have to inject second feature's dependencies as well. So I think app module should have its own application class.

Even if we set (or write a new) application class for the app module, we can not do this for instantapp module, because it does not contain any code.

To sum up: We can use manifest merger's rules to select an application class for app and instantapp modules. But I think having two application classes won't work because instantapp module does not allow any code.

So right now I'm not sure how to organize application classes for Instant Apps. Maybe we should stop using application classes and move those codes inside activity classes in feature modules.

Ps: I created a question on StackOverflow.

doanappdev commented 6 years ago

Hi,

thank you for your reply, I have a solution which uses your example of dagger2 for a feature module called app, this has the manifest file with "android:name=.MyApplication" and in another feature module I use this:

object DaggerProvider {

    private lateinit var featureComponent: FeatureComponent

    fun getFeatureComponent(context: Context): FeatureComponent {
        featureComponent = DaggerFeatureComponent.builder()
                .bindContext(context)
                .repoModule(RepositoryModule())
                .appComponent(BaseApplication.appComponent)
                .build()

        return featureComponent
    }
}
@ActivityScoped
@Component(
        dependencies = arrayOf(AppComponent::class),
        modules = arrayOf(RepositoryModule::class))
interface FeatureComponent {

    fun inject(activity: VehicleDetailsActivity)

    @Component.Builder
    interface Builder {
        @BindsInstance
        fun bindContext(cxt: Context): Builder
        fun repoModule(repository: RepositoryModule): Builder
        fun appComponent(component: AppComponent): Builder
        fun build(): FeatureComponent
    }
}

In activity I call DaggerProvider.getFeatureComponent(applicationContext).inject(this); In the second feature module I do not set "android:name" in the manifest.

I use kotlin in my project, if you would like me to make a pull request let me know. It would be good to add this to your example as other people might be wondering how to use dagger2 with other feature module

mustafaberkaymutlu commented 6 years ago

Thanks for your help, I really appreciate it!

I started this project with Dagger.Android in mind, but apparently we cannot have seperate application classes for each feature modules (as ManmeetP states here). We can only have instant and installed Application classes.

Having Dagger.Android in Activity classes instead of Application is pretty much straight Dagger. So I started trying to solve this issue by moving injection codes into Activity classes. I also removed the Dagger.Android and use just good-old Dagger.

So I injected dependencies as you suggested. But I don't like the idea of keeping a static reference of Dagger components, therefore I didn't add DaggerProvider.

I created a new feature called AutoComplete, it's empty now but I could inject the Presenter and ViewState in AutoCompleteActivity without any problem.

If you like to see the diff, take a look at here.

doanappdev commented 6 years ago

I agree having static reference is not ideal, i think putting it in base class was good idea. After reading google docs about instant apps, it seems the android manifest files get merged into a single manifest file, therefore its not recommended to have multiple application tags with "android:name".

The tricky part with instant apps is you have to consider both situations i.e. normal app and instant app.

Your repository was great help when learning about creating and configuring instant app. And with this update it will help others when they look for solution on how to setup instant app with multiple feature modules and Dagger2.

Thanks