Few things are more frustrating to a mobile user than being forcibly blocked by an update modal.
Imagine you are standing at a checkout counter, or reconciling an urgent bank balance. You open your finance app to log an expense, and the screen is held hostage by a full-screen, un-dismissible popup: "Update Required! Tap here to open Google Play."
You tap update, wait for a 40MB download over a weak cellular connection, watch the installation progress, and by the time the app re-opens, you have forgotten the transaction details.
Forced immediate updates alienate users. But ignoring updates completely leaves users running outdated schemas, missing critical bug fixes, or lacking security patches.
In FinLedger (commit 90c352f), we solved this by implementing the Google Play In-App Updates API using a non-intrusive Flexible Download workflow.
Here is how that lifecycle is engineered.
Immediate vs. Flexible Updates
The Google Play Core In-App Update API provides two distinct user flows:
flowchart TD
subgraph UpdateStrategies["Google Play Update Strategies"]
direction TB
Immediate["1. Immediate Update (Blocking):
Full-screen modal. Blocks UI completely. Forces download & install before app can be used."]
Flexible["2. Flexible Update (Non-Intrusive):
Prompts user once. Downloads in the background while user continues using the app. Shows subtle restart banner when ready."]
end
When to Use Immediate Updates
Immediate updates should be reserved exclusively for critical emergencies:
- A severe security vulnerability where un-patched versions cannot safely execute.
- A breaking API change or database migration bug where continuing to use the older version causes irrevocable data corruption.
Why Financial Apps Need Flexible Updates
For routine feature updates, performance improvements, and minor bug fixes, Flexible Updates are vastly superior:
- The user is shown a standard Google Play bottom sheet asking if they wish to download the update.
- If they accept, the update downloads silently in the background while they continue creating accounts, logging transactions, or reviewing budgets.
- If they decline or are busy, the prompt dismisses gracefully and does not nag them again during that session.
The Flexible Update Lifecycle State Machine
Implementing Flexible Updates properly requires managing an asynchronous state machine:
stateDiagram-v2
[*] --> CheckAvailability : App Launch
CheckAvailability --> NoUpdate : Update Not Available
CheckAvailability --> UpdateAvailable : Update Available (AppUpdateInfo)
UpdateAvailable --> PromptUser : Request Flexible Flow
PromptUser --> UserDeclined : User Dismisses
PromptUser --> Downloading : User Accepts
Downloading --> Downloading : Background Progress
Downloading --> Downloaded : InstallStatus.DOWNLOADED
Downloaded --> ShowRestartBanner : Display Persistent In-App Snack
ShowRestartBanner --> Restarting : User Taps 'Restart'
Restarting --> [*] : completeUpdate()
1. Checking Availability
On cold app startup, the UpdateManager queries the Google Play Store client:
- It checks
appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE. - It verifies that the update is allowed to run flexibly:
appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.FLEXIBLE).
2. Background Download Monitoring
Once the user accepts the flexible update prompt:
- An
InstallStateUpdatedListenermonitors background progress. - As the APK chunks download, the app remains fully responsive.
- When the download completes, the listener receives
InstallStatus.DOWNLOADED.
3. The Non-Intrusive Restart Banner
When an update finishes downloading, Android does not forcefully kill the app to install it. That would risk corrupting an active SQLite transaction!
Instead, FinLedger surfaces a subtle, high-contrast banner at the top of the screen:
- "An update has been downloaded. Restart to apply the latest improvements."
- The banner includes a Restart Now action button and a dismiss option.
- When the user finishes logging their transactions and taps Restart, the app cleanly flushes its Room database connections, closes open cursors, and invokes
appUpdateManager.completeUpdate().
Google Play seamlessly restarts the application with the new version running in less than two seconds.
Handling the Resume Edge Case
A common developer bug with flexible updates occurs when an update finishes downloading while the app is minimized in the background.
When the user re-opens the app hours later, the listener never fired while the app was asleep.
To resolve this:
- FinLedger re-checks
appUpdateManager.appUpdateInfoinMainActivity.onResume(). - If the status is already
InstallStatus.DOWNLOADED, the restart banner is immediately mounted on screen, ensuring the user is notified even if the download completed while the phone was locked.
Key Takeaway
Respecting user autonomy extends to how you ship software updates.
By implementing Google Play Flexible In-App Updates with non-intrusive background downloads and explicit restart controls, FinLedger keeps users on the latest, most secure build without ever interrupting their financial workflow.
FinLedger is a privacy-first, offline-first personal finance application for Android that models bank accounts, credit cards, and cash without double-counting.
Explore FinLedger on Google Play: https://play.google.com/store/apps/details?id=com.devanshufinance.app

Top comments (0)