Search code examples
androiddagger

Better Dagger dependency injection based on build type and flavor?


I am using aproach to provide modules to Dagger described in answer of this question Android Customize Workflow for Product Flavors

Our approach is a bit different - we have Modules in debug build type in src/debug/java and in release build type in src/release/java. Our main module is called ApplicationModule it includes all other.

Modules in src/debug/java provides some custom behaviour for debugging, logging etc and overrides ApplcationModule.

Now we have a need to have custom behaviour based on application flavor.

What would be correct approach to do that?

For example flavors A to C should provide custom behaviours, while flavors D to F should provide basic, default behaviour.

So far I came up with such.

  • All flavors (not build types) has same class in src/flavorX/java/com.application.FlavorModule
  • To avoid code duplication only flavors A to C provide custom behavior while other completely empty so that project would compile. And default behaviour is provided my module in src/main/java

Is there a better way to achieve such result? Because I don't like empty src/flavorX/java/com.application.FlavorModule and don't like code duplication...


Solution

  • Little complicated but here's how I did it:

    Create an interface MainComponent and keep it in src/main, this should contain anything that is not flavor specific

    public interface MainComponent {
        void inject(MyApplication o);
    
        void inject(BusinessObject o);
    
        Foo getFoo();
    
        Activitycomponent plusActivityComponent(ActivityModule activityModule);
    

    }

    Within each flavor create an interface that inherits from the above one

    public interface FlavorComponent extends MainComponent {
    //flavor specific injection stuff similar to SourceComponent
    }
    

    Within Debug/Beta/Release create the actual component and extend the FlavorComponent (giving you all the flavor specific niceties).

    @Singleton
     @Component(modules = {ApplicationModule.class, FlavorModule.class,
             BetaApplicationModule.class, AnotherModuleJustBecause.class})
    public interface ApplicationComponent extends FlavorComponent {
         void inject(NYTApplication a);
    
     }
    

    Notice that you can also include a flavor specific FlavorModule that can be different in each flavor or not include it in Release while including it in Beta.

    Also include a ComponentFactory within Debug/Beta/Release returning the common Flavor Component Interface

    public class ComponentFactory {
    
    public static final FlavorComponent getComponent(Application context) {
            return DaggerApplicationComponent.builder()
                    .applicationModule(new ApplicationModule(context))
                    .build();
        }
    

    and finally from your Application class call:

    ComponentFactory.getComponent(this).inject(this);
    

    The component factory will return the Build Type Component which will extend the Flavor's Component.