flutter_alone 3.1.0 copy "flutter_alone: ^3.1.0" to clipboard
flutter_alone: ^3.1.0 copied to clipboard

PlatformWindows

A Flutter plugin for preventing duplicate execution of desktop applications with customizable message support and cross-user detection

example/lib/main.dart

import 'dart:io';

import 'package:flutter/material.dart';
import 'package:flutter_alone/flutter_alone.dart';
import 'package:system_tray/system_tray.dart';
import 'package:window_manager/window_manager.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await windowManager.ensureInitialized();

  WindowOptions windowOptions = const WindowOptions(
    size: Size(500, 800),
    center: true,
    title: 'Tray App Example',
  );
  windowManager.waitUntilReadyToShow(windowOptions, () async {
    await windowManager.show();
    await windowManager.focus();
  });

  if (Platform.isWindows) {
    // Example 1: DefaultMutexConfig (Legacy method)
    // final defaultConfig = FlutterAloneConfig(
    //   // Legacy mutex config using packageId and appName
    //   mutexConfig: const DefaultMutexConfig(
    //     packageId: 'com.example.myapp',
    //     appName: 'MyFlutterApp',
    //     mutexSuffix: 'production',
    //   ),

    //   // Window configuration
    //   windowConfig: const WindowConfig(
    //     windowTitle: 'Tray App Example',
    //   ),

    //   // Debug mode setting
    //   duplicateCheckConfig: const DuplicateCheckConfig(
    //     enableInDebugMode: true,
    //   ),

    //   // Custom message configuration
    //   messageConfig: const CustomMessageConfig(
    //     customTitle: 'Example App',
    //     customMessage: 'Application is already running in another account',
    //     showMessageBox: true,
    //   ),
    // );

    // Example 2: CustomMutexConfig (Recommended method)
    final customConfig = FlutterAloneConfig(
      // Custom mutex name
      mutexConfig: const CustomMutexConfig(
        customMutexName: 'MyUniqueApplicationMutex',
      ),

      // Window configuration
      windowConfig: const WindowConfig(
        windowTitle: 'Tray App Example',
      ),

      // Debug mode setting
      duplicateCheckConfig: const DuplicateCheckConfig(
        enableInDebugMode: true,
      ),

      // Default English messages
      messageConfig: const EnMessageConfig(),
    );

    final config = customConfig; // or use defaultConfig

    if (!await FlutterAlone.instance.checkAndRun(config: config)) {
      exit(0);
    }
  }

  runApp(const MyApp());
}

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

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final SystemTray _systemTray = SystemTray();

  @override
  void initState() {
    super.initState();
    _initSystemTray();
  }

  @override
  void dispose() {
    FlutterAlone.instance.dispose();
    super.dispose();
  }

  Future<void> _initSystemTray() async {
    String path =
        Platform.isWindows ? 'assets/app_icon.ico' : 'assets/app_icon_64.png';
    if (!await File(path).exists()) {
      debugPrint("Icon file not found: $path");
    }

    await _systemTray.initSystemTray(iconPath: path);

    _systemTray.setTitle('Flutter alone example');
    _systemTray.setToolTip('Flutter alone example');

    final Menu menu = Menu();
    await menu.buildFrom([
      MenuItemLabel(
        label: 'Open',
        onClicked: (_) async {
          await windowManager.show();
          await windowManager.focus();
        },
      ),
      MenuItemLabel(
        label: 'Exit',
        onClicked: (_) async {
          await _systemTray.destroy();
          exit(0);
        },
      ),
    ]);

    await _systemTray.setContextMenu(menu);

    _systemTray.registerSystemTrayEventHandler(
      (eventName) async {
        if (eventName == kSystemTrayEventClick) {
          if (Platform.isWindows) {
            await windowManager.show();
            await windowManager.focus();
          } else {
            await _systemTray.popUpContextMenu();
          }
        } else if (eventName == kSystemTrayEventRightClick) {
          if (Platform.isWindows) {
            await _systemTray.popUpContextMenu();
          } else {
            await windowManager.show();
            await windowManager.focus();
          }
        }
      },
    );
  }

  Future<void> hideWindow() async {
    await windowManager.hide();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Flutter Alone Example'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              const Text(
                'The app ran normally.',
                style: TextStyle(fontSize: 18),
              ),
              const SizedBox(height: 20),
              const Text(
                'Prevent duplicate execution with custom mutex:',
                style: TextStyle(fontSize: 14),
              ),
              const Text(
                'Using CustomMutexConfig with name: MyUniqueApplicationMutex',
                style: TextStyle(fontSize: 14),
              ),
              const SizedBox(height: 20),
              ElevatedButton(
                onPressed: hideWindow,
                child: const Text('Hide window'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
1
likes
160
points
207
downloads

Publisher

unverified uploader

Weekly Downloads

A Flutter plugin for preventing duplicate execution of desktop applications with customizable message support and cross-user detection

Repository (GitHub)
View/report issues

Documentation

Documentation
API reference

License

MIT (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on flutter_alone