Setting Up Dynamic Feature Modules for Android Apps

One of our clients, a food delivery app, faced a problem: the built-in AR module for viewing dishes weighed 23 MB of additional resources. Statistics showed that only 8% of users opened this feature. The remaining 92% uselessly downloaded 23 MB with every installation. Our solution was to extract th

Development and support of all types of mobile applications:

Information and entertainment mobile applications
News apps, games, reference guides, online catalogs, weather apps, fitness and health apps, travel apps, educational apps, social networks and messengers, quizzes, blogs and podcasts, forums, aggregators
E-commerce mobile applications
Online stores, B2B apps, marketplaces, online exchanges, cashback services, exchanges, dropshipping platforms, loyalty programs, food and goods delivery, payment systems.
Business process management mobile applications
CRM systems, ERP systems, project management, sales team tools, financial management, production management, logistics and delivery management, HR management, data monitoring systems
Electronic services mobile applications
Classified ads platforms, online schools, online cinemas, electronic service platforms, cashback platforms, video hosting, thematic portals, online booking and scheduling platforms, online trading platforms

These are just some of the types of mobile applications we work with, and each of them may have its own specific features and functionality, tailored to the specific needs and goals of the client.

Showing 1 of 1All 1734 services
Setting Up Dynamic Feature Modules for Android Apps
Complex
~3-5 days

Our competencies:

Frequently Asked Questions

Latest works

  • image_mobile-applications_feedme_467_0.webp
    Development of a mobile application for FEEDME
    895
  • image_mobile-applications_xoomer_471_0.webp
    Development of a mobile application for XOOMER
    782
  • image_mobile-applications_rhl_428_0.webp
    Development of a mobile application for RHL
    1216
  • image_mobile-applications_zippy_411_0.webp
    Development of a mobile application for ZIPPY
    1079
  • image_mobile-applications_affhome_429_0.webp
    Development of a mobile application for Affhome
    1002
  • image_mobile-applications_flavors_409_0.webp
    Development of a mobile application for the FLAVORS company
    597

One of our clients, a food delivery app, faced a problem: the built-in AR module for viewing dishes weighed 23 MB of additional resources. Statistics showed that only 8% of users opened this feature. The remaining 92% uselessly downloaded 23 MB with every installation. Our solution was to extract the AR module into a Dynamic Feature Module with on-demand delivery. Now the module is only downloaded by those who tap "View in AR." The base APK size decreased by 30%, reducing the cost per install by $0.15 per user (saving $7500 at 50,000 installs). The conversion to AR usage increased by 15% due to the absence of extra weight during installation. DFM is 2–3 times more efficient than monolithic architecture in terms of APK size.

Why Move Features to Dynamic Feature Modules?

Every megabyte of the base APK is a loss of conversion. According to Google Play Developer Documentation, every 10 MB of installation package reduces the probability of installation by 1–2%. DFMs allow loading only critical functionality at startup and the rest on demand. This improves first launch speed by 85% and reduces traffic consumption. In practice, we see a reduction in base installation size of 40–60% for apps with 2–3 infrequent features. For example, for an app with 500,000 MAU, traffic savings are about 300 GB per month. Using DFM can be 5 times more effective than traditional multi-APK splitting.

How to Configure Dynamic Feature Module with On-Demand Delivery?

Let's go through the step-by-step process of configuring a DFM with on-demand delivery. Assume minSdk = 21 (Android 5.0), compileSdk = 34, Kotlin 1.9, AGP 8.0.

  1. Create a new module with the com.android.dynamic-feature plugin. In build.gradle, specify a dependency on the base module (implementation(project(":app"))).
  2. In the app/build.gradle, add the module to the dynamicFeatures list.
  3. Use SplitInstallManager to download the module:
val manager = SplitInstallManagerFactory.create(context) val request = SplitInstallRequest.newBuilder() .addModule("feature_ar") .build() manager.startInstall(request) .addOnSuccessListener { sessionId -> // module is installing, sessionId for tracking } .addOnFailureListener { exception -> // handle SplitInstallException } 
  1. Handle the REQUIRES_USER_CONFIRMATION state if the module is larger than 10 MB. Show a dialog explaining the benefits of the feature.

Project Architecture with DFM

The project is restructured into a multi-module architecture. The app becomes the base module — it contains only critical startup functionality (entry point, shared resources). Heavy or rarely used features are extracted into separate dynamic feature modules. For example, if the base app weighs 50 MB, and the extracted module is 20 MB, after migration the base size will be 30 MB.

// dynamic feature module build.gradle plugins { id("com.android.dynamic-feature") } android { defaultConfig { minSdk = 21 } } dependencies { implementation(project(":app")) // dependency on base module } 

In app/build.gradle:

android { dynamicFeatures += setOf(":feature_ar", ":feature_premium") } 

Comparison of Installation Modes

Mode Attribute When Used Size Limitation
Install-time dist:install-time Features needed immediately (e.g., main screen) None (included in APK)
On-demand dist:on-demand Rare features (AR, premium filters) Available after install
Conditional dist:conditions Features dependent on Android version, region, or OpenGL ES support Automatic installation when conditions are met

Install-time modules do not reduce base size, but participate in slicing (delivery only for your architecture). On-demand is the main tool for size reduction. Conditional is for features that not everyone needs but can be installed automatically.

Comparison of Navigation Approaches in DFM

Approach Stack Complexity Flexibility
Jetpack Navigation with include-dynamic Navigation Component Medium High
Custom Router via ServiceLocator Without Navigation Component High Full

Jetpack Navigation is easier to integrate but requires a dependency on the library. Custom Router gives full control but increases development time.

Problems during Implementation

Navigation. From the base module, you cannot import classes from DFM directly (circular dependency). Navigation is built via Intent with explicit class name as a string or via Navigation Component with include-dynamic. @Navigator with DynamicNavHostFragment is the correct way for Jetpack Navigation:

<navigation> <include-dynamic android:id="@+id/ar_graph" android:name="com.example.feature_ar" app:moduleName="feature_ar" app:graphResId="@navigation/ar_navigation" /> </navigation> 

SplitCompat. To access resources and classes of the installed DFM, you need to enable SplitCompat in Application:

override fun attachBaseContext(base: Context) { super.attachBaseContext(base) SplitCompat.install(this) } 

Without this, ClassNotFoundException when trying to use a class from a newly installed module — a common mistake.

Testing. DFMs do not work on a regular APK build — only when installed via Play Store or via bundletool. For local development, we use bundletool install-apks or internal testing track in Play Console. Writing a test without considering this limitation wastes a day.

Session State. SplitInstallSessionState goes through several states: PENDING → DOWNLOADING → INSTALLING → INSTALLED. For modules larger than 10 MB, Google requires showing a confirmation dialog to the user (SplitInstallException with code REQUIRES_USER_CONFIRMATION). Must be handled, otherwise the installation is interrupted.

Common Mistakes - Missing SplitCompat installation - Not handling user confirmation for large modules - Using feature classes before module is fully installed

Case: Navigation via DFM without Jetpack Navigation

In a client project built on a custom Router, we had to implement lazy-loading of modules without Jetpack Navigation. The solution: a FeatureProvider interface in the base module, implementation in the DFM via ServiceLocator. The DFM registers its FeatureProvider when loaded via reflection (the only case where it is justified — specifically for DFM bootstrapping). The base module requests FeatureProvider through SplitInstallManager.installedModules.

Deliverables for DFM Setup

  • Audit of current architecture and candidate identification for extraction
  • Design of multi-module structure considering navigation and dependencies
  • Implementation of on-demand or install-time modules
  • Configuration of SplitInstallManager and handling of all session states
  • Integration with Navigation Component or custom Router
  • Testing with bundletool on real devices
  • Documentation on build and deployment
  • Access to code repository and CI/CD pipeline
  • Training session for your team (2 hours)
  • Ongoing support for 1 month after project completion

Timeline and Cost

Setting up one DFM module with navigation takes 3–5 days. Migrating an existing monolithic app to multi-module with several DFMs takes 2–4 weeks depending on code coupling. The average cost of implementing a DFM is $2500, leading to an estimated $5000 annual savings. The cost of setting up one module ranges from $1500 to $3500, full migration from $5000 to $15000. Implementation pays off on average in 4 months (savings of ~$5000 per year for an app with 50k installs).

We have been doing Android development for over 5 years and have completed 20+ DFM projects. We guarantee correct operation of all loading scenarios and absence of SplitCompat errors. Order DFM setup from us and get an engineer consultation. Contact us for an audit of your project.