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

Tips for implementing Android Dynamic Feature Module

Tips for implementing Android Dynamic Feature Module

At CA.apk#9, I have talked about the merit for implementing features with Dynamic Feature Module (DFM), and shared some tips for implementing features with DFM.

---

Official Docs
* Android App Bundles | Android Developers
https://developer.android.com/guide/app-bundle

* About Dynamic Delivery  |  Android Developers
https://developer.android.com/guide/app-bundle/dynamic-delivery

* About Conditional Delivery | Android Developers
https://developer.android.com/guide/app-bundle/conditional-delivery

---

Other Presentations regarding DFM(JP)
* Dynamic Feature Module in Practice
https://speakerdeck.com/star_zero/droidkaigi-2020

---

Other Links
* R8 & DataBinding with DFM
https://stackoverflow.com/questions/54404492/proguard-with-appbundle-and-data-binding-illegalstateexception
https://issuetracker.google.com/issues/139046605

* Delivery Config - Apk
https://stackoverflow.com/questions/54844007/how-to-generate-full-apk-file-including-dynamic-feature-module

* Jacoco Config
https://github.com/arturdm/jacoco-android-gradle-plugin/issues/80
https://github.com/vanniktech/gradle-android-junit-jacoco-plugin/pull/158

Shohei Kawano

July 14, 2020
Tweet

More Decks by Shohei Kawano

Other Decks in Technology

Transcript

  1. Why DFM? ・”Ability to customize how and when the feature

    to be downloaded onto devices running Android 5.0”  ・Reduce initial App install size https://developer.android.com/guide/app-bundle/dynamic-delivery
  2. Why DFM? 0 17 34 Without DFM with DFM Initial

    App Intall Size ※Estimate
  3. R8 & DataBinding // dynamic-feature-module/build.gradle buildFeatures { dataBinding = true

    } // dynamic-feature-module/DynamicActivity.kt DataBindingUtil.setContentView(this, layoutId) // app/build.gradle release { minifyEnabled = true }
  4. R8 & DataBinding // dynamic-feature-module/build.gradle buildFeatures { dataBinding = true

    } // dynamic-feature-module/DynamicActivity.kt DataBindingUtil.setContentView(this, layoutId) Release Build // app/build.gradle release { minifyEnabled = true }
  5. R8 & DataBinding //dynamic-feature-module/build.gradle buildFeatures { dataBinding = true }

    // DynamicActivity.kt DataBindingUtil.setContentView(this, layoutId) Release Build //app/build.gradle release { minifyEnabled = true } RuntimeException java.lang.RuntimeException: Unable to start activity ComponentInfo{...DynamicActivity}: java.lang.IllegalStateException: DataBindingUtil.setConte… R.layout.dynamic_activity) must not be null Caused by: java.lang.IllegalStateException: DataBindingUtil.setConte… R.layout.dynamic_activity) must not be null at DynamicActivity.onCreate(DynamicActivity.kt:38)
  6. # dynamic-feature-module/proguard-rules-dynamic-features.pro -keep class your.dfm.package.name.DataBinderMapperImpl { *; } https://issuetracker.google.com/issues/139046605 R8

    & DataBinding https://stackoverflow.com/questions/54404492/proguard-with-appbundle-and-data-binding-illegalstateexception // dynamic-feature-module/build.gradle buildTypes { release { proguardFiles 'proguard-rules-dynamic-features.pro' } }
  7. <!-- dynamic-feature-module/AndroidManifest.xml —> <dist:module dist:instant="false" dist:title="@string/dfm_module_name"> <dist:delivery> <dist:on-demand /> </dist:delivery>

    </dist:module> $ ./gradlew install{Flavor}Debug or Delivery Config - Install ActivityNotFoundException android.content.ActivityNotFoundException: Unable to find explicit activity class {com.your.dfm.package.name.DynamicActivity}; have you declared this activity in your AndroidManifest.xml?
  8. <!-- dynamic-feature-module/AndroidManifest.xml —-> <dist:module dist:instant="false" dist:title="@string/dfm_module_name"> <dist:fusing dist:include="true" /> <dist:delivery>

    <dist:install-time /> </dist:delivery> </dist:module> Delivery Config - Apk https://developer.android.com/guide/app-bundle/dynamic-delivery ・Include module in multi-APKs for device running Android 4.4 or lower
  9. <!-- dynamic-feature-module/AndroidManifest.xml —-> <dist:module dist:instant="false" dist:title="@string/dfm_module_name"> <dist:fusing dist:include="true" /> <dist:delivery>

    <dist:install-time /> </dist:delivery> </dist:module> Delivery Config - Apk https://developer.android.com/guide/app-bundle/dynamic-delivery ・Include module in the universal APK using bundletool ・Include module in multi-APKs for device running Android 4.4 or lower
  10. <!-- dynamic-feature-module/AndroidManifest.xml —-> <dist:module dist:instant="false" dist:title="@string/dfm_module_name"> <dist:fusing dist:include="true" /> <dist:delivery>

    <dist:install-time /> </dist:delivery> </dist:module> Delivery Config - Apk $ ./gradlew package{Flavor}DebugUniversalApk $ ./gradlew package{Flavor}ReleaseUniversalApk https://stackoverflow.com/questions/54844007/how-to-generate-full-apk-file-including-dynamic-feature-module
  11. <!-- dynamic-feature-module/AndroidManifest.xml —-> <dist:module dist:instant="false" dist:title="@string/dfm_module_name"> <dist:fusing dist:include="true" /> <dist:delivery>

    <dist:install-time /> </dist:delivery> </dist:module> Delivery Config - Apk Debugging → install-time Releasing → on-demand
  12. Delivery Config - Apk <!-- dynamic-feature-module/AndroidManifest.xml —-> <dist:module dist:instant="false" dist:title="@string/dfm_module_name">

    <dist:fusing dist:include="true" /> <dist:delivery> <dist:on-demand /> <dist:install-time> <dist:conditions> </dist:conditions> </dist:install-time> </dist:delivery> </dist:module>
  13. <!-- dynamic-feature-module/AndroidManifest.xml —-> <dist:module dist:instant="false" dist:title="@string/dfm_module_name"> <dist:fusing dist:include="true" /> <dist:delivery>

    <dist:on-demand /> <dist:install-time> <dist:conditions> </dist:conditions> </dist:install-time> </dist:delivery> </dist:module> Delivery Config - Apk https://developer.android.com/guide/app-bundle/conditional-delivery Requirements for DFM to be downloaded during app install
  14. Delivery Config - Apk <!-- dynamic-feature-module/AndroidManifest.xml —-> <dist:module dist:instant="false" dist:title="@string/dfm_module_name">

    <dist:fusing dist:include="true" /> <dist:delivery> <dist:on-demand /> <dist:install-time> <dist:conditions> </dist:conditions> </dist:install-time> </dist:delivery> </dist:module>
  15. <!-- dynamic-feature-module/AndroidManifest.xml -—> <dist:module dist:instant="false" dist:title="dfm_module_name"> <dist:fusing dist:include="${include_fusing}" /> <dist:delivery>

    <dist:on-demand /> <dist:install-time> <dist:conditions> <dist:user-countries dist:exclude="${exclude_install_time}"> <dist:country dist:code="JP" /> </dist:user-countries> </dist:conditions> </dist:install-time> </dist:delivery> </dist:module> Delivery Config - Apk
  16. <!-- dynamic-feature-module/AndroidManifest.xml -—> <dist:module dist:instant="false" dist:title="dfm_module_name"> <dist:fusing dist:include="${include_fusing}" /> <dist:delivery>

    <dist:on-demand /> <dist:install-time> <dist:conditions> <dist:user-countries dist:exclude="${exclude_install_time}"> <dist:country dist:code="JP" /> </dist:user-countries> </dist:conditions> </dist:install-time> </dist:delivery> </dist:module> Delivery Config - Apk Do not include DFM during install-time if ‘exclude’ is true
  17. <!-- dynamic-feature-module/AndroidManifest.xml -—> <dist:module dist:instant="false" dist:title="dfm_module_name"> <dist:fusing dist:include="${include_fusing}" /> <dist:delivery>

    <dist:on-demand /> <dist:install-time> <dist:conditions> <dist:user-countries dist:exclude="${exclude_install_time}"> <dist:country dist:code="JP" /> </dist:user-countries> </dist:conditions> </dist:install-time> </dist:delivery> </dist:module> Delivery Config - Apk Include DFM during install-time for this country code
  18. <!-- dynamic-feature-module/AndroidManifest.xml -—> <dist:module dist:instant="false" dist:title="dfm_module_name"> <dist:fusing dist:include="${include_fusing}" /> <dist:delivery>

    <dist:on-demand /> <dist:install-time> <dist:conditions> <dist:user-countries dist:exclude="${exclude_install_time}"> <dist:country dist:code="JP" /> </dist:user-countries> </dist:conditions> </dist:install-time> </dist:delivery> </dist:module> Delivery Config - Apk Manifest Placeholder to toggle based on Product Flavor
  19. <!-- dynamic-feature-module/AndroidManifest.xml -—> <dist:module dist:instant="false" dist:title="dfm_module_name"> <dist:fusing dist:include="${include_fusing}" /> <dist:delivery>

    <dist:on-demand /> <dist:install-time> <dist:conditions> <dist:user-countries dist:exclude="${exclude_install_time}"> <dist:country dist:code="JP" /> </dist:user-countries> </dist:conditions> </dist:install-time> </dist:delivery> </dist:module> Delivery Config - Apk
  20. // dynamic-feature-module/build.gradle productFlavors { flavor1 { manifestPlaceholders = [include_fusing: true,

    exclude_install_time: false] } flavor2 { manifestPlaceholders = [include_fusing: false, exclude_install_time: true] } } ... Delivery Config - Apk
  21. Jacoco Config // root/build.gradle dependencies { classpath ‘com.dicedmelon.gradle:jacoco-android:0.1.4' } //

    dfm/build.gradle apply plugin: 'jacoco-android' * What went wrong: A problem occurred evaluating script. > Failed to apply plugin [id 'jacoco-android'] > You must apply the Android plugin or the Android library plugin before using the jacoco-android plugin
  22. Tips Why DFM? — To reduce App Install Size —

    Keep DataBinderMapperImpl — Configure delivery options Carefully — Use fusing / include option for APK — Use manifest placeholder if necessary — Some Jacoco android gradle plugin(s) just do not work with DFM Conclusion