Flutter单实例控制插件flutter_single_instance的使用

发布于 1周前 作者 nodeper 来自 Flutter

Flutter Single Instance

A simple way to check if your application is already running.

Platform Support
Android ⚠️
iOS ⚠️
Web ⚠️
macOS
Windows
Linux

✅ - Confirmed working.
⚠️ - Always reports as first instance.

Installation

Add flutter_single_instance as a dependency in your pubspec.yaml file.

flutter pub add flutter_single_instance

macOS

Disable sandboxing and enable networking in macos/Runner/DebugProfile.entitlements and macos/Runner/Release.entitlements files.

<key>com.apple.security.app-sandbox</key>
<false/>

<key>com.apple.security.network.server</key>
<true/>

<key>com.apple.security.network.client</key>
<true/>
  • com.apple.security.app-sandbox: Set to false to allow access to the filesystem.
  • com.apple.security.network.server: Set to true to allow the app to act as a server and listen for incoming focus requests.
  • com.apple.security.network.client: Set to true to allow the app to act as a client and send focus requests to the server (i.e., the main instance).

Usage

A simple usage example:

import 'dart:io';

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

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

  if (await FlutterSingleInstance().isFirstInstance()) {
    runApp(const MyApp());
  } else {
    print("App is already running");

    final err = await FlutterSingleInstance().focus();

    if (err != null) {
      print("Error focusing running instance: $err");
    }

    exit(0);
  }
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

Web and Other Unsupported Platforms

You can safely use this package in web and other unsupported platforms. It will always return true for the isFirstInstance method.

Limitations

  • Currently, this package does not provide a way to bring the existing instance to the front. If you have any ideas on how to achieve this, please open an issue or a pull request. (This limitation has been resolved in version 1.2.0.)

Example

For a complete example, you can refer to the example/lib/main.dart file in the repository.

import 'dart:io';

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

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

  if (await FlutterSingleInstance().isFirstInstance()) {
    runApp(const MyApp());
  } else {
    print("App is already running");

    final err = await FlutterSingleInstance().focus();

    if (err != null) {
      print("Error focusing running instance: $err");
    }

    exit(0);
  }
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

This example demonstrates how to use the flutter_single_instance package to ensure that only one instance of your Flutter application runs at a time. If another instance is detected, it will attempt to bring the existing instance to the front and then exit.


更多关于Flutter单实例控制插件flutter_single_instance的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter单实例控制插件flutter_single_instance的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter中,flutter_single_instance 插件用于确保应用在同一设备上只能有一个实例运行。这对于避免数据冲突和用户体验问题非常有用。以下是如何在Flutter项目中使用 flutter_single_instance 插件的一个示例代码案例。

步骤 1: 添加依赖

首先,在你的 pubspec.yaml 文件中添加 flutter_single_instance 依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_single_instance: ^x.y.z  # 替换为最新版本号

然后运行 flutter pub get 来获取依赖。

步骤 2: 导入并使用插件

在你的主文件(通常是 main.dart)中,导入并使用 flutter_single_instance 插件。以下是一个完整的示例:

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

void main() async {
  // 检查是否为单实例
  bool isSingleInstance = await FlutterSingleInstance.checkSingleInstance();

  if (isSingleInstance) {
    runApp(MyApp());
  } else {
    // 如果不是单实例,可以选择退出应用或显示提示
    exit(0);
    // 或者显示一个提示对话框(这里为了简单直接退出)
  }
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Single Instance Demo'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You are running the single instance of this app.',
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {},
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

解释

  1. 检查单实例:在 main 函数中,使用 FlutterSingleInstance.checkSingleInstance() 方法来检查当前应用是否为单实例运行。这个方法是异步的,因此需要使用 await 关键字。

  2. 运行应用或退出:如果应用是单实例,则继续运行 MyApp。如果不是单实例,则可以选择退出应用(这里使用了 exit(0))。你也可以选择显示一个对话框给用户提示。

注意事项

  • 在某些平台上(特别是Android),你可能需要在 AndroidManifest.xml 中添加一些配置来确保单实例行为,但 flutter_single_instance 插件通常已经处理了这些平台特定的细节。
  • 确保在每次应用启动时都进行单实例检查,以避免潜在的并发实例问题。

通过上述代码示例,你可以在Flutter应用中有效地实现单实例控制。

回到顶部