firebase_update
Control Flutter releases with updates, maintenance mode, and live configuration.
Qoder
9 sectionsFlutter Package
Overview
firebase_update gives Flutter apps server-controlled release behavior through Firebase Remote Config. Product and engineering teams can block unsupported builds, suggest optional upgrades, turn on maintenance mode, and show patch notes without waiting for a new app release.
Features
Everything needed for production update control, with defaults that work and hooks for teams that need branded surfaces.
- Force Update — blocks app usage when a breaking release is required
- Optional Update — encourages upgrade via a dismissible dialog or bottom sheet
- Maintenance Mode — instantly gates the app without shipping a new build
- Real-time Remote Config propagation — changes apply without app restart
- Patch notes displayed in plain text or HTML alongside the update prompt
- FirebaseUpdateBuilder — reactive widget for custom in-screen update surfaces
- Fully custom UI builders — override one, two, or all three surfaces independently
- Store-version fallback checks when listing data is useful
Installation
Requires Firebase to already be set up in your app.
dependencies:
firebase_update: ^1.0.0Quick Start
Call initialize() once during app bootstrap, after Firebase.initializeApp(). Pass the same navigatorKey to your MaterialApp. The package then listens for Remote Config changes and automatically presents the appropriate UI.
import 'package:firebase_update/firebase_update.dart';
final navigatorKey = GlobalKey<NavigatorState>();
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
await FirebaseUpdate.instance.initialize(
navigatorKey: navigatorKey,
config: const FirebaseUpdateConfig(),
);
runApp(MyApp(navigatorKey: navigatorKey));
}
// Pass the same navigatorKey to MaterialApp
MaterialApp(
navigatorKey: navigatorKey,
home: const HomeScreen(),
)Remote Config Schema
Create a parameter named firebase_update_config in Firebase Remote Config, or pass a custom key. Priority order is intentionally strict: maintenance mode wins over force update, and force update wins over optional update.
{
"min_version": "2.0.0",
"latest_version": "2.3.1",
"maintenance_message": "",
"patch_notes": "• Bug fixes\n• Performance improvements",
"patch_notes_format": "text"
}- min_version — minimum supported version; below this triggers a blocking force update
- latest_version — latest available version; below this triggers an optional update
- maintenance_message — non-empty string activates maintenance mode (blocking)
- force_update_title & force_update_message — override the force update screen copy
- patch_notes — release notes shown alongside the prompt (format: text or html)
Custom UI & Theming
Override any surface directly on FirebaseUpdateConfig. Each builder receives resolved presentation data, state, action labels, and callbacks, so teams can keep update flows consistent with their brand and navigation model.
// Override individual surfaces
FirebaseUpdateConfig(
forceUpdateWidget: (context, data) => MyForceUpdateDialog(data: data),
optionalUpdateWidget: (context, data) => MyUpdateSheet(data: data),
maintenanceWidget: (context, data) => MyMaintenanceScreen(data: data),
)
// Theme the default UI
FirebaseUpdatePresentation(
theme: FirebaseUpdatePresentationTheme(
accentColor: Colors.indigo,
accentForegroundColor: Colors.white,
surfaceColor: Colors.white,
heroGradient: LinearGradient(
colors: [Colors.indigo.shade800, Colors.indigo.shade400],
),
dialogBorderRadius: BorderRadius.circular(24),
),
)Reactive Widget
Use FirebaseUpdateBuilder to build your own in-screen update surfaces — a settings row, a banner, or anything that should react to update state.
FirebaseUpdateBuilder(
builder: (context, state) {
if (state.kind == FirebaseUpdateKind.optionalUpdate) {
return UpdateBanner(version: state.latestVersion);
}
return const SizedBox.shrink();
},
)API Reference
Core API for controlling update behavior programmatically.
// Initialize once at app startup
await FirebaseUpdate.instance.initialize(
navigatorKey: navigatorKey,
config: config,
);
// Force an immediate fetch and re-evaluate state
await FirebaseUpdate.instance.checkNow();
// Current state (synchronous) or stream (reactive)
FirebaseUpdateState state = FirebaseUpdate.instance.currentState;
Stream<FirebaseUpdateState> stream = FirebaseUpdate.instance.stream;
// Apply a raw payload manually (useful in tests)
await FirebaseUpdate.instance.applyPayload({'min_version': '2.0.0'});Testing
A Dart CLI tool in test/firebase_config/ pushes predefined scenarios directly to Firebase Remote Config, leaving all other parameters untouched. The running app reacts in real time.
cd test/firebase_config
dart pub get
# Push test scenarios:
dart run update_remote_config.dart optional
dart run update_remote_config.dart force
dart run update_remote_config.dart maintenance
dart run update_remote_config.dart clear