app_update_check 1.0.0 copy "app_update_check: ^1.0.0" to clipboard
app_update_check: ^1.0.0 copied to clipboard

Check the App Store / Google Play for a newer version, show an optional or forced update dialog, and detect TestFlight builds. Zero dependencies.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:app_update_check/app_update_check.dart';

void main() {
  // Optional. Without it the running app's own bundle id / application id is
  // used. A numeric iosId gives a store link even when the lookup fails.
  AppUpdate.init(
    // androidId: 'com.plant.identification.care',
    // iosId: '6762586391',
    // iosCountry: 'vn',
  );
  runApp(const ExampleApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'app_update_check example',
      theme: ThemeData(colorSchemeSeed: Colors.green, useMaterial3: true),
      home: const ExampleHomePage(),
    );
  }
}

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

  @override
  State<ExampleHomePage> createState() => _ExampleHomePageState();
}

class _ExampleHomePageState extends State<ExampleHomePage> {
  LocalAppInfo? _local;
  AppUpdateStatus? _status;
  bool _busy = false;
  bool _simulateUpdate = false;

  @override
  void initState() {
    super.initState();
    _loadLocal();
    // Typical usage: check once the first screen is up.
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (mounted) AppUpdate.showUpdateDialogIfNeeded(context);
    });
  }

  Future<void> _loadLocal() async {
    final LocalAppInfo local = await AppUpdate.getLocalInfo();
    if (mounted) setState(() => _local = local);
  }

  Future<void> _run(Future<void> Function() action) async {
    setState(() => _busy = true);
    try {
      await action();
    } finally {
      if (mounted) setState(() => _busy = false);
    }
  }

  Future<void> _check() => _run(() async {
    final AppUpdateStatus status = await AppUpdate.check(refresh: true);
    if (mounted) setState(() => _status = status);
  });

  Future<void> _showDialog({bool force = false}) => _run(() async {
    final AppUpdateStatus status = await AppUpdate.showUpdateDialogIfNeeded(
      context,
      force: force,
      showReleaseNotes: true,
    );
    if (mounted) setState(() => _status = status);
  });

  void _toggleSimulation(bool value) {
    setState(() => _simulateUpdate = value);
    // Re-configure the shared checker. `forceStoreVersion` pretends the store
    // has version 99.0.0 so the dialog can be tried without publishing.
    AppUpdate.init(forceStoreVersion: value ? '99.0.0' : null);
  }

  @override
  Widget build(BuildContext context) {
    final LocalAppInfo? local = _local;
    final AppUpdateStatus? status = _status;
    return Scaffold(
      appBar: AppBar(title: const Text('app_update_check')),
      body: ListView(
        padding: const EdgeInsets.all(16),
        children: <Widget>[
          _Section(
            title: 'This build',
            rows: <MapEntry<String, String>>[
              MapEntry('Version', local?.version ?? '...'),
              MapEntry('Build', local?.buildNumber ?? '...'),
              MapEntry('Package', local?.packageName ?? '...'),
              MapEntry('Install source', local?.installSource.name ?? '...'),
              MapEntry('TestFlight', '${local?.isTestFlight ?? '...'}'),
            ],
          ),
          const SizedBox(height: 16),
          _Section(
            title: 'Store',
            rows: <MapEntry<String, String>>[
              MapEntry('Store version', status?.storeVersion ?? '-'),
              MapEntry(
                'Update available',
                '${status?.isUpdateAvailable ?? '-'}',
              ),
              MapEntry('Update type', status?.updateType.name ?? '-'),
              MapEntry('Ahead of store', '${status?.isAheadOfStore ?? '-'}'),
              MapEntry('Store URL', status?.storeUrl ?? '-'),
              MapEntry('Error', status?.error?.toString() ?? '-'),
            ],
          ),
          const SizedBox(height: 16),
          SwitchListTile(
            title: const Text('Simulate a newer store version (99.0.0)'),
            value: _simulateUpdate,
            onChanged: _toggleSimulation,
          ),
          const SizedBox(height: 8),
          FilledButton(
            onPressed: _busy ? null : _check,
            child: const Text('Check now'),
          ),
          const SizedBox(height: 8),
          FilledButton.tonal(
            onPressed: _busy ? null : () => _showDialog(),
            child: const Text('Show update dialog if needed'),
          ),
          const SizedBox(height: 8),
          FilledButton.tonal(
            onPressed: _busy ? null : () => _showDialog(force: true),
            child: const Text('Show FORCE update dialog if needed'),
          ),
          const SizedBox(height: 8),
          OutlinedButton(
            onPressed: _busy ? null : () => _run(AppUpdate.openStore),
            child: const Text('Open store'),
          ),
          if (_busy) ...<Widget>[
            const SizedBox(height: 16),
            const Center(child: CircularProgressIndicator()),
          ],
        ],
      ),
    );
  }
}

class _Section extends StatelessWidget {
  const _Section({required this.title, required this.rows});

  final String title;
  final List<MapEntry<String, String>> rows;

  @override
  Widget build(BuildContext context) {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(12),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Text(title, style: Theme.of(context).textTheme.titleMedium),
            const SizedBox(height: 8),
            for (final MapEntry<String, String> row in rows)
              Padding(
                padding: const EdgeInsets.symmetric(vertical: 2),
                child: Row(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: <Widget>[
                    SizedBox(width: 130, child: Text(row.key)),
                    Expanded(child: SelectableText(row.value)),
                  ],
                ),
              ),
          ],
        ),
      ),
    );
  }
}
0
likes
160
points
66
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Check the App Store / Google Play for a newer version, show an optional or forced update dialog, and detect TestFlight builds. Zero dependencies.

Repository (GitHub)
View/report issues

Topics

#version #update #testflight #app-store #play-store

License

MIT (license)

Dependencies

flutter

More

Packages that depend on app_update_check

Packages that implement app_update_check