fl_updater 0.1.0 copy "fl_updater: ^0.1.0" to clipboard
fl_updater: ^0.1.0 copied to clipboard

Firebase Remote Config-driven app update dialog with automatic wrapper, snoozable soft updates, and native App/Play Store opening.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:fl_updater/fl_updater.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  try {
    await Firebase.initializeApp();
  } catch (error) {
    // If Firebase isn't configured yet, fl_updater fails open safely.
    // To connect to a live Firebase project, run `flutterfire configure` inside the example/ directory.
    debugPrint('Firebase.initializeApp notice: $error');
  }
  runApp(const ExampleApp());
}

// Replace with your real identifiers:
// - On iOS, the numeric App Store ID (e.g. '123456789') is required.
// - On Android, the package ID defaults to the host application if omitted.
const _iosAppId = '123456789';
const _androidPackageId = 'com.kishormainali.fl_updater_example';

class ExampleApp extends StatelessWidget {
  const ExampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'fl_updater Example',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      // FlUpdaterWrapper automatically evaluates update status on launch
      builder: (context, child) => FlUpdaterWrapper(
        iosAppId: _iosAppId,
        androidPackageId: _androidPackageId,
        // enabled is forced to true here for example/testing purposes.
        // In production apps, omit this (it defaults to !kDebugMode) so debug
        // builds don't consume Remote Config quota during development.
        enabled: true,
        enableLogging: true,
        child: child!,
      ),
      home: const HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  final _updater = FlUpdater();
  UpdateInfo? _lastCheckedInfo;
  bool _isLoading = false;

  Future<void> _checkManually() async {
    setState(() => _isLoading = true);
    try {
      final info = await _updater.checkForUpdate(
        iosAppId: _iosAppId,
        androidPackageId: _androidPackageId,
        enabled: true,
      );
      setState(() => _lastCheckedInfo = info);
      if (mounted) {
        await _updater.showUpdateDialog(
          context,
          info: info,
          iosAppId: _iosAppId,
          androidPackageId: _androidPackageId,
          enabled: true,
        );
      }
    } finally {
      if (mounted) {
        setState(() => _isLoading = false);
      }
    }
  }

  Future<void> _showStyledDialog() async {
    await _updater.showUpdateDialog(
      context,
      iosAppId: _iosAppId,
      androidPackageId: _androidPackageId,
      enabled: true,
      title: '🚀 Major Update Available!',
      message:
          'A brand-new version is ready with exciting features and enhancements.',
      updateButtonText: 'Upgrade Now',
      laterButtonText: 'Remind Me Later',
      style: FlUpdaterDialogStyle(
        backgroundColor: Colors.deepPurple.shade50,
        titleStyle: const TextStyle(
          fontWeight: FontWeight.bold,
          color: Colors.deepPurple,
          fontSize: 20,
        ),
        messageStyle: const TextStyle(color: Colors.black87, fontSize: 14),
        shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
        icon:
            const Icon(Icons.rocket_launch, size: 40, color: Colors.deepPurple),
      ),
    );
  }

  Future<void> _showCustomBuilderDialog() async {
    await _updater.showUpdateDialog(
      context,
      iosAppId: _iosAppId,
      androidPackageId: _androidPackageId,
      enabled: true,
      dialogBuilder: (dialogContext, info, onUpdate, onLater) {
        final isForce = info.status == UpdateStatus.force;
        return AlertDialog(
          icon: const Icon(Icons.stars, color: Colors.amber, size: 36),
          title: Text('Custom Dialog: ${info.latestVersion}'),
          content: Text(
            'Current version is ${info.currentVersion}.\n\n'
            'This dialog was rendered using a custom dialogBuilder callback.',
          ),
          actions: [
            if (!isForce)
              TextButton(
                onPressed: onLater,
                child: const Text('Dismiss & Snooze'),
              ),
            FilledButton.icon(
              onPressed: onUpdate,
              icon: const Icon(Icons.download),
              label: const Text('Download Update'),
            ),
          ],
        );
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('fl_updater Example'),
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
      ),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(20.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            Card(
              elevation: 0,
              color: Theme.of(context).colorScheme.surfaceContainerHighest,
              child: const Padding(
                padding: EdgeInsets.all(16.0),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      'Firebase Remote Config Integration',
                      style:
                          TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
                    ),
                    SizedBox(height: 8),
                    Text(
                      'Set a fl_updater_config String parameter in your Firebase '
                      'Remote Config Console with a JSON value, e.g.:\n'
                      '{"latest_version": "2.0.0", "min_version": "1.5.0"}',
                      style: TextStyle(fontSize: 13),
                    ),
                  ],
                ),
              ),
            ),
            const SizedBox(height: 20),
            if (_lastCheckedInfo != null) ...[
              Card(
                child: Padding(
                  padding: const EdgeInsets.all(16.0),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      const Text(
                        'Last Evaluation Result',
                        style: TextStyle(fontWeight: FontWeight.bold),
                      ),
                      const Divider(),
                      Text(
                          'Current Version: ${_lastCheckedInfo!.currentVersion}'),
                      Text(
                          'Latest Version: ${_lastCheckedInfo!.latestVersion}'),
                      Text('Status: ${_lastCheckedInfo!.status.name}'),
                    ],
                  ),
                ),
              ),
              const SizedBox(height: 20),
            ],
            FilledButton.icon(
              onPressed: _isLoading ? null : _checkManually,
              icon: _isLoading
                  ? const SizedBox(
                      width: 18,
                      height: 18,
                      child: CircularProgressIndicator(strokeWidth: 2),
                    )
                  : const Icon(Icons.refresh),
              label: const Text('Check for Update (Default Dialog)'),
            ),
            const SizedBox(height: 12),
            OutlinedButton.icon(
              onPressed: _showStyledDialog,
              icon: const Icon(Icons.palette),
              label: const Text('Show Styled Dialog Demo'),
            ),
            const SizedBox(height: 12),
            OutlinedButton.icon(
              onPressed: _showCustomBuilderDialog,
              icon: const Icon(Icons.dashboard_customize),
              label: const Text('Show Custom Builder Dialog Demo'),
            ),
          ],
        ),
      ),
    );
  }
}
0
likes
160
points
286
downloads

Documentation

API reference

Publisher

verified publisherkishormainali.com

Weekly Downloads

Firebase Remote Config-driven app update dialog with automatic wrapper, snoozable soft updates, and native App/Play Store opening.

Repository (GitHub)
View/report issues

Topics

#app-update #remote-config #firebase #in-app-update #updater

License

MIT (license)

Dependencies

firebase_remote_config, flutter, fp_logger, package_info_plus, plugin_platform_interface, shared_preferences

More

Packages that depend on fl_updater

Packages that implement fl_updater