Rolling back an offline app is a data exercise as much as a software exercise. Reinstalling an earlier build may not reverse a database migration, recover queued writes, or reconcile changes made while disconnected. Test the app package, local state, and synchronization behavior as separate parts of one recovery plan.
State what rollback means
Name the versions involved: current app, candidate app, local schema, sync protocol, and server API. Define the desired end state. It may be a return to the earlier binary with current user data preserved, a forward repair that restores compatibility, or a backup restore into a known-good release. Those outcomes are not interchangeable.
Identify the app’s source of truth before designing the test. Android’s offline-first architecture guidance recommends that higher layers read from the local data source and explains that local and network state can diverge. It also notes that offline writes may require versioning and conflict resolution when connectivity returns. A rollback test must therefore cover both disconnected use and reconnection.
Build a representative test state
Use test accounts and synthetic records, not copied production data. Seed the earlier app version with several kinds of state: records that have synced, records created offline, edits pending upload, a deletion, preferences, an attachment if supported, and an item that will conflict with a server-side edit. Record stable identifiers and expected values for each item.
Create and verify a backup before the change. A file merely labeled “backup” is not proof of recovery. Android’s backup and restore testing guide uses a cycle that modifies app state, triggers backup, clears or reinstalls the app, restores the data, and then validates that state was retained. Adapt that sequence to the product’s supported backup mechanism.
Exercise the migration and reversal
Install the candidate version while offline. Open every critical screen, read existing records, create and edit data, close the app, and reopen it. Capture crashes, schema errors, missing records, and unexpected default values. Then invoke the documented rollback method without ad-libbing steps.
Database compatibility is the hard boundary. Android’s Room migration guidance recommends retaining exported schema history and testing all defined migrations. It also warns that destructive migration fallback permanently deletes table data when no migration path exists. Do not use a destructive fallback as a convenient rollback unless loss of that test data is the explicitly intended and approved behavior.
If the older binary cannot safely read the newer schema, the plan should stop rather than force a downgrade. The recovery may need to restore a compatible backup or deploy a forward fix. Record this as a design constraint, not a failed operator step.
Test reconnection and conflicts
After local rollback appears successful, reconnect under controlled conditions. Observe the pending-write queue. Verify that each queued action is sent once, acknowledged, and removed or retained according to the app’s design. Exercise the prepared conflict and record which version wins, what the user sees, and whether any data becomes unreachable. Repeat with interrupted connectivity so the queue is tested across a retry, not only a clean network.
Check that the restored app does not overwrite newer server data merely because its local timestamps or version markers changed during restore. If the product cannot guarantee a safe conflict outcome, the rollback procedure should keep synchronization disabled until support or an administrator reviews the account.
Define pass criteria
A passing result accounts for every seeded record, preserves required preferences and attachments, opens without schema errors, processes queued work without duplication, produces the documented conflict result, and leaves server and local state reconcilable. It also records elapsed recovery time and who made the go/no-go decision.
Keep the build identifiers, schema versions, test data manifest, backup identifier, migration logs, queued-operation results, conflict observations, and final validation. Rerun the rehearsal after changing storage, synchronization, authentication, encryption, or backup rules. The goal is not merely to launch an old screen; it is to return the user’s work to a supported, explainable state.
Sources
- Build an offline-first app — Android Developers
- Test backup and restore — Android Developers
- Migrate your Room database — Android Developers