On-demand dynamic feature module persistence under storage pressure
0 reputation · 11 Sept 2022, 18:56 UTC
0 reputation · 11 Sept 2022, 18:56 UTC
This Android App Bundle configures an on-demand dynamic feature module (dist:onDemand="true") using Android Gradle Plugin 8.0+ and Play Core 1.10+. The goal is to keep the module installed after SplitInstallManager.startInstall() completes so the app does not lose access to its resources and code at runtime.
The system may silently uninstall dynamic feature modules to free storage, and the documentation does not define the eviction policy, priority ordering, or whether user-requested installs are treated differently from deferred installs. No manifest flag such as dist:removable="false" applies to on-demand modules, and SplitInstallManager exposes no persistence API or uninstallation callback.
Behavior varies by Play Store version, Android API level, and OEM storage management, so a single-device test is not sufficient.
Is there a supported way to mark an on-demand dynamic feature module as non-removable? If not, what signals can the app rely on to detect silent uninstallation before the user attempts to use module functionality?
33775 reputation · 12 Sept 2022, 02:37 UTC
There is no supported way to mark a dynamic feature module configured with dist:onDemand="true" as non-removable. The dist:removable="false" attribute does not apply to on-demand modules, and the SplitInstallManager API provides no mechanism to lock a module in storage or prevent the Play Store from reclaiming space under storage pressure.
Because the Play Store manages the lifecycle of on-demand modules to optimize device storage, it may silently uninstall modules without notifying the application. This behavior is undocumented and varies based on the Play Store version, the Android API level, and OEM-specific storage management heuristics. Crucially, SplitInstallManager does not provide an uninstallation callback; the SplitInstallStateUpdatedListener only tracks the progress of active installation requests, not the removal of existing modules.
Since you cannot prevent eviction, the app must treat the presence of a dynamic module as a transient state. You can rely on the following signals and patterns to detect and handle missing modules:
SplitInstallManager.getInstalledModules(). If the module name is absent from the returned set, the module has been evicted.try-catch block to handle ClassNotFoundException or Resources.NotFoundException, which may occur if eviction happens between the check and the execution.SplitInstallManager.startInstall() again to restore functionality.// Example verification check
Set<String> installedModules = splitInstallManager.getInstalledModules();
if (!installedModules.contains("my_feature_module")) {
// Trigger re-installation flow
splitInstallManager.startInstall(request);
}
startInstall() and verify its presence in getInstalledModules().SplitInstallStateUpdatedListener events are fired during the silent removal process.Diagnostic Detail Needed: Are you using a custom ClassLoader or a specific dependency injection framework (like Hilt) to access the module? This may change how you implement the runtime guards to avoid crashes during silent eviction.
Use comments to ask for clarification. Post a solution as an answer.
33,775 reputation · 12 Sept 2022, 00:17 UTC
Eviction of on-demand dynamic feature modules depends on Play Store version, Android API level, and OEM storage policies rather than the on-demand installation type. Unlike install-time modules, no dist:removable="false" equivalent exists to prevent silent removal. For reliable detection, cross-check SplitInstallManager.getInstalledModules() against PackageManager.getPackageInfo() for the split APK path: if the split file is absent from the filesystem or no active session is recorded, the module has been evicted. This check helps avoid false positives from ProGuard or resource renaming.