Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Multimodularization Scaling Android app

Avatar for Rohit Singh Rohit Singh
November 02, 2019

Multimodularization Scaling Android app

Breaking techniques using examples. Patterns needed to follow when you want to expose navigation or data from feature modules.

Avatar for Rohit Singh

Rohit Singh

November 02, 2019

Other Decks in Programming

Transcript

  1. ├── app ├── features │ ├── transport │ ├── food

    │ └── payments └── resources ├── layout ├── activity_transport.xml ├── activity_food.xml └── activity_payments.xml
  2. ├── transport └── resource ├── layout ├── activity_transport.xml ├── food

    └── resource ├── layout ├── activity_food.xml ├── payments └── resource ├── layout ├── activity_payments.xml ├── app ├── features │ ├── transport │ ├── food │ └── payments └── resources ├── layout ├── activity_transport.xml ├── activity_food.xml └── activity_payments.xml
  3. ├── transport └── resource ├── layout ├── activity_transport.xml ├── food

    └── resource ├── layout ├── activity_food.xml ├── payments └── resource ├── layout ├── activity_payments.xml ├── app ├── features │ ├── transport │ ├── food │ └── payments └── resources ├── layout ├── activity_transport.xml ├── activity_food.xml └── activity_payments.xml
  4. ├── transport └── resource ├── layout ├── activity_transport.xml ├── food

    └── resource ├── layout ├── activity_food.xml ├── payments └── resource ├── layout ├── activity_payments.xml ├── app ├── features │ ├── transport │ ├── food │ └── payments └── resources ├── layout ├── activity_transport.xml ├── activity_food.xml └── activity_payments.xml
  5. For every 6 MB increase to an APK’s size, we

    see a decrease in the install conversion rate of 1%. - Google Play Apps & Games
  6. apply plugin: 'com.android.library' apply plugin: 'kotlin' apply plugin: 'java-library' :common

    :network :logger :utils :analytics :styles Core Module :app :transport :food :payments
  7. Monolithic Architecture ├── app ├── features │ ├── transport │

    ├── food │ └── payments └── resources ├── layout ├── activity_transport.xml ├── activity_food.xml └── activity_payments.xml Navigation Intent(context, PaymentActivity:class.java)
  8. Modualrize Architecture Navigation ├──payments └── resource ├── layout ├── activity_payments.xml

    ├── transport └── resource ├── layout ├── activity_transport.xml Independent Modules Transport Module should not depend on payments module
  9. App Component inside app grade module @AppScope @Component( modules =

    [ CoreModule::class] ) interface AppComponent { fun inject(app: App) }
  10. Payments exposes Interface in payments-bridge module interface PaymentsNavigationUseCase { fun

    navigateToPaymentMethodScreen(context: Context) } interface PaymentsDataProvider { fun provideBalanceStream() : Observable<Data> }
  11. Interface Implementation exposed as Dagger Module inside payments @Module object

    PaymentsNavigation Module { @Provides @JvmStatic fun provideNavigationUsecase() : PaymentsNavigationUseCase = PaymentsNavigationUseCaseImpl() } @Module object PaymentsDataProviderModule { @Provides @JvmStatic fun providesPaymentsDataProvider() : PaymentsDataProvider = PaymentsDataProviderImpl() }
  12. App Component inside app grade module @AppScope @Component( modules =

    [ CoreModule::class, PaymentsNavigation Module::class, PaymentsDataProviderModule::class] ) interface AppComponent { fun inject(app: App) }
  13. Transport Component @Component( dependencies = [TransportActivityComponentParent::class] ) interface TransportActivityComponent {

    fun inject(activity: TransportActivity) } interface TransportComponentParent { fun paymentsNavigationUseCase(): PaymentsNavigationUseCase fun commonObject(): CommonObject }
  14. Transport Component @Component( dependencies = [TransportActivityComponentParent::class] ) interface TransportActivityComponent {

    fun inject(activity: TransportActivity) } interface TransportComponentParent { fun featureOneNavigationUseCase(): PaymentsNavigationUseCase fun commonObject(): CommonObject }
  15. @AppScope @Component( modules = [ CoreModule::class, PaymentsNavigationModule::class, PaymentsDataProviderModule::class] ) interface

    AppComponent : TransportComponentParent { fun inject(app: App) } App Component inside app grade module
  16. inline fun <reified T : Any> Context.parent(): T? { var

    ctx = this while (ctx !is Application) { ctx = ctx.applicationContext } if(ctx is ParentHost){ return ctx.extractParent<T>() } return null } Extension Function
  17. Application Class class DemoApp : Application(), ParentHost { override fun

    <T> extractParent(): T { return component as T } lateinit var component: AppComponent override fun onCreate() { super.onCreate() component = DaggerAppComponent.create() component.inject(this) } }
  18. Summary 1. Split Payments into 2 modules: “Payment interface” &

    “Payment implementation” 2. Include payment interface module inside transport module 3. Transport module relies on payment interface and its implementation is provided by app.
  19. Module A Module B Module C app Module D Module

    E Module F api implementation
  20. Module A Module B Module C app Module D Module

    E Module F api implementation
  21. Module A Module B Module C app Module D Module

    E Module F api implementation
  22. Build Process For Library Dependencies Preparation Merging Resources & Processing

    Manifest Compiling Postprocessing Packaging & publishing
  23. Build Process For Library Dependencies Preparation Merging Resources & Processing

    Manifest Compiling Postprocessing Packaging & publishing