flutter_in_store_app_version_checker 3.1.0-dev.1 copy "flutter_in_store_app_version_checker: ^3.1.0-dev.1" to clipboard
flutter_in_store_app_version_checker: ^3.1.0-dev.1 copied to clipboard

A lightweight Flutter plugin to check app versions in Google Play, Apple App Store, ApkPure, RuStore, and AppGallery

example/lib/main.dart

import 'dart:async';
import 'dart:developer' as dev show log;

import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_in_store_app_version_checker/flutter_in_store_app_version_checker.dart';

/// A pair of store IDs for `Google Play` and `App Store`,
/// containing a current version of the app.
typedef StoreIDPair = ({
  String googlePlayID,
  String appleStoreID,
  String currentVersion,
});

// TikTok
// bundle id: com.zhiliaoapp.musically, https://www.ntc.swiss/hubfs/NTC-security-analysis-tiktok-v1.0-en.pdf?utm_source=chatgpt.com
const StoreIDPair kTikTokStoreIDPair = (
  googlePlayID: 'com.zhiliaoapp.musically',
  appleStoreID: 'com.zhiliaoapp.musically',
  currentVersion: '43.7.0',
);

// Roblox
// bundle id: com.roblox.robloxmobile, https://apptopia.com/ios/app/431946152/about?utm_source=chatgpt.com
const StoreIDPair kRobloxStoreIDPair = (
  googlePlayID: 'com.roblox.client',
  appleStoreID: 'com.roblox.robloxmobile',
  currentVersion: '2.706.752',
);

// Free Fire (TH)
// bundle id: com.dts.freefireth, https://apptopia.com/ios/app/1300146617/about?utm_source=chatgpt.com
const StoreIDPair kFreefirethStoreIDPair = (
  googlePlayID: 'com.dts.freefireth',
  appleStoreID: 'com.dts.freefireth',
  currentVersion: '1.120.1',
);

// Wildberries
// bundle id из AASA wildberries.ru, https://well-known.dev/resources/apple_app_site_association/sites/wildberries.ru?utm_source=chatgpt.com
const StoreIDPair kWildberriesStoreIDPair = (
  googlePlayID: 'com.wildberries.ru',
  appleStoreID: 'RU.WILDBERRIES.MOBILEAPP',
  currentVersion: '',
);

// OZON
// bundle id (аналитика/ASO источники): ru.ozon.OzonStore, https://platform.foxdata.com/en/app-profile/407804998/BY/as?utm_source=chatgpt.com
const StoreIDPair kOzonStoreIDPair = (
  googlePlayID: 'ru.ozon.app.android',
  appleStoreID: 'ru.ozon.OzonStore',
  currentVersion: '',
);

const _tetradkaPackageName = 'ru.beautybox.twa';
const _tetradkaAppGalleryStoreID = 'C107631977';
const _tetradkaCurrentVersion = '38.2.0';

void main() => runZonedGuarded<void>(
  () => runApp(const App()),
  (e, s) => dev.log('Top level exception: $e\n$s'),
);

/// {@template app}
/// App widget.
/// {@endtemplate}
class App extends StatelessWidget {
  /// {@macro app}
  const App({super.key});

  @override
  Widget build(BuildContext context) => MaterialApp(
    title: 'In Store App Version Checker Example',
    theme: ThemeData.dark(),
    home: const Example(),
  );
}

/// {@template example}
/// Example widget of using the `InStoreAppVersionChecker` plugin.
/// {@endtemplate}
class Example extends StatefulWidget {
  /// {@macro example}
  const Example({super.key});

  @override
  State<Example> createState() => _ExampleState();
}

/// State of the [Example] widget.
class _ExampleState extends State<Example> {
  final ValueNotifier<bool> _updating = ValueNotifier<bool>(false);
  final _checker = InStoreAppVersionChecker.instance;
  Future<void>? _checkFuture;

  InStoreAppVersionCheckerResponse? _wildberries,
      _freefireth,
      _roblox,
      _tiktok,
      _ozon,
      _ruStore,
      _appGallery,
      _appGalleryNative;

  /// Whether the app is running on Android.
  bool get _isAndroid => defaultTargetPlatform == .android;

  /// Whether the app is running on iOS.
  bool get _isIOS => defaultTargetPlatform == .iOS; // ignore: unused_element

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    _checkFuture ??= _checkVersion();
  }

  @override
  void dispose() {
    _updating.dispose();
    super.dispose();
  }

  /// Create [InStoreAppVersionCheckerParams] for a given [StoreIDPair].
  InStoreAppVersionCheckerParams _paramsFor(StoreIDPair storeIDPair) =>
      InStoreAppVersionCheckerParams(
        currentVersion: storeIDPair.currentVersion,
        packageName: _isAndroid
            ? storeIDPair.googlePlayID
            : storeIDPair.appleStoreID,
        locale: View.of(context).platformDispatcher.locale.toLanguageTag(),
      );

  String get _locale =>
      View.of(context).platformDispatcher.locale.toLanguageTag();

  /// Check the current version of the app available in app stores
  /// such as `AppStore`, `Google Play`, `ApkPure`, `RuStore`, and `AppGallery`,
  /// comparing it with the installed version on the device.
  Future<void> _checkVersion() async {
    final stopwatch = Stopwatch()..start();
    try {
      await <Future<void>>[
        _checker
            .checkUpdate(_paramsFor(kOzonStoreIDPair))
            .then((r) => _ozon = r),
        _checker
            .checkUpdate(_paramsFor(kRobloxStoreIDPair))
            .then((r) => _roblox = r),
        _checker
            .checkUpdate(_paramsFor(kTikTokStoreIDPair))
            .then((r) => _tiktok = r),
        _checker
            .checkUpdate(_paramsFor(kFreefirethStoreIDPair))
            .then((r) => _freefireth = r),
        _checker
            .checkUpdate(_paramsFor(kWildberriesStoreIDPair))
            .then((r) => _wildberries = r),
        if (_isAndroid) ...<Future<void>>[
          _checker
              .checkUpdate(
                InStoreAppVersionCheckerParams(
                  locale: _locale,
                  packageName: _tetradkaPackageName,
                  currentVersion: _tetradkaCurrentVersion,
                  androidStore:
                      InStoreAppVersionCheckerAndroidStoreType.ruStore,
                ),
              )
              .then((r) => _ruStore = r),
          _checker
              .checkUpdate(
                InStoreAppVersionCheckerParams(
                  locale: _locale,
                  packageName: _tetradkaPackageName,
                  storeID: _tetradkaAppGalleryStoreID,
                  currentVersion: _tetradkaCurrentVersion,
                  androidStore:
                      InStoreAppVersionCheckerAndroidStoreType.appGallery,
                ),
              )
              .then((r) => _appGallery = r),
          _checker
              .checkUpdate(
                InStoreAppVersionCheckerParams(
                  locale: _locale,
                  androidStore:
                      InStoreAppVersionCheckerAndroidStoreType.appGalleryNative,
                ),
              )
              .then((r) => _appGalleryNative = r),
        ],
      ].wait;
    } on Object catch (e, _) {
      if (!mounted) return;
      ScaffoldMessenger.of(context)
        ..hideCurrentSnackBar()
        ..showSnackBar(
          SnackBar(
            content: Text(
              'Error checking for updates: $e',
              style: Theme.of(
                context,
              ).textTheme.bodyLarge?.copyWith(color: Colors.white),
            ),
            backgroundColor: CupertinoDynamicColor.resolve(
              CupertinoColors.systemRed,
              context,
            ),
          ),
        );
    } finally {
      dev.log(
        '${(stopwatch..stop()).elapsedMicroseconds / 10000} μs',
        name: 'check_version',
        level: 100,
      );
    }
  }

  Future<void> _refresh() async {
    _updating.value = true;
    final future = _checkVersion();
    setState(() => _checkFuture = future);
    await future;
    if (mounted) _updating.value = false;
  }

  @override
  Widget build(BuildContext context) => Scaffold(
    appBar: AppBar(
      centerTitle: true,
      title: const Text(
        'In Store App Version Checker Example',
        style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600),
      ),
      actions: <Widget>[
        IconButton(
          iconSize: 24,
          padding: .zero,
          onPressed: _refresh,
          icon: const Icon(CupertinoIcons.refresh),
        ),
      ],
    ),
    body: SafeArea(
      child: Padding(
        padding: const .all(16),
        child: ValueListenableBuilder(
          valueListenable: _updating,
          builder: (_, updating, _) => FutureBuilder(
            future: _checkFuture,
            builder: (context, snapshot) {
              // --- Loading state --- //
              if (updating || snapshot.connectionState == .waiting) {
                return Center(
                  child: Column(
                    mainAxisAlignment: .center,
                    spacing: 8,
                    children: <Widget>[
                      const SizedBox.square(
                        dimension: 18,
                        child: CircularProgressIndicator.adaptive(
                          strokeWidth: 2,
                          strokeCap: .round,
                        ),
                      ),
                      Text(updating ? 'Updating...' : 'Loading...'),
                    ],
                  ),
                );
              }

              // --- Error state --- //
              if (snapshot.hasError) {
                return Center(
                  child: Text(
                    'Error: ${snapshot.error}',
                    style: TextStyle(
                      color: CupertinoDynamicColor.resolve(
                        CupertinoColors.systemRed,
                        context,
                      ),
                    ),
                  ),
                );
              }

              return SingleChildScrollView(
                child: Column(
                  spacing: 16,
                  children: <Widget>[
                    StoreResultSection(title: 'Ozon', item: _ozon),
                    StoreResultSection(
                      title: 'Wildberries',
                      item: _wildberries,
                    ),
                    StoreResultSection(title: 'Roblox', item: _roblox),
                    StoreResultSection(title: 'Tik Tok', item: _tiktok),
                    StoreResultSection(title: 'Freefeireth', item: _freefireth),
                    if (_isAndroid) ...<Widget>[
                      StoreResultSection(
                        title: 'Tetradka · RuStore',
                        item: _ruStore,
                      ),
                      StoreResultSection(
                        title: 'Tetradka · AppGallery web',
                        item: _appGallery,
                      ),
                      StoreResultSection(
                        title: 'Installed app · AppGallery native',
                        item: _appGalleryNative,
                      ),
                    ],
                  ],
                ),
              );
            },
          ),
        ),
      ),
    ),
  );
}

/// Displays a store-check result.
/// {@macro example}
class StoreResultSection extends StatelessWidget {
  /// {@macro main}
  const StoreResultSection({
    required this.title,
    required this.item,
    super.key, // ignore: unused_element_parameter
  });

  final String title;
  final InStoreAppVersionCheckerResponse? item;

  @override
  Widget build(BuildContext context) {
    final response = item;
    final (status, color) = switch (response) {
      null => ('Not checked', CupertinoColors.systemGrey),
      _ when response.isError => ('Error', CupertinoColors.systemRed),
      _ when response.canUpdate => ('Can update', CupertinoColors.systemGreen),
      _ => ('Up to date', CupertinoColors.systemBlue),
    };
    final resolvedColor = CupertinoDynamicColor.resolve(color, context);

    return SizedBox(
      width: double.infinity,
      child: Column(
        crossAxisAlignment: .start,
        spacing: 5,
        children: <Widget>[
          Row(
            spacing: 10,
            children: <Widget>[
              Flexible(
                child: Text(
                  title,
                  style: const TextStyle(fontWeight: .w600, fontSize: 17),
                ),
              ),
              Badge(
                label: Text(status),
                textColor: resolvedColor,
                backgroundColor: resolvedColor.withAlpha(25),
                padding: const .symmetric(horizontal: 8, vertical: 3),
              ),
            ],
          ),
          if (response == null)
            const Text('No result yet.')
          else if (response.isError)
            Text(
              response.errorMessage ?? 'Unknown store error.',
              style: TextStyle(color: resolvedColor),
            )
          else ...<Widget>[
            Text('Current version: ${response.currentVersion}'),
            Text('Store version: ${response.newVersion ?? 'not reported'}'),
            Text('App URL: ${response.appURL ?? 'not reported'}'),
          ],
        ],
      ),
    );
  }
}
14
likes
160
points
3.43k
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A lightweight Flutter plugin to check app versions in Google Play, Apple App Store, ApkPure, RuStore, and AppGallery

Repository (GitHub)
View/report issues
Contributing

Funding

Consider supporting this project:

www.buymeacoffee.com
boosty.to

License

MIT (license)

Dependencies

flutter, http, meta

More

Packages that depend on flutter_in_store_app_version_checker

Packages that implement flutter_in_store_app_version_checker