Flutter应用前后台状态管理插件flutter_fgbg的使用

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

Flutter应用前后台状态管理插件flutter_fgbg的使用

Flutter Foreground/Background Event Notifier

flutter_fgbg 是一个Flutter插件,用于检测应用程序(不是Flutter容器)何时进入后台或前台。

为什么需要这个插件?

Flutter本身提供了 WidgetsBindingObserver 类来监听应用程序状态的变化,从活跃到非活跃状态以及返回。但是它实际上也包括了嵌入式Activity/ViewController的状态变化。因此,如果你有一个打开新activity/view controller的插件,或者在iOS上启动FaceID提示,那么 WidgetsBindingObserver 会报告应用程序处于非活跃/恢复状态。而这个插件只报告应用级别的事件。在iOS中,插件报告 didEnterBackgroundNotificationwillEnterForegroundNotification 通知,在Android中,则使用 androidx.lifecycle:lifecycle-process 包来报告这些事件。对于其他平台,插件则回退到使用 AppLifecycleListener API 来获取信号。

你可以查看 example/ 项目以了解实际中的差异。

开始使用

添加依赖

首先将插件添加到你的 pubspec.yaml 文件中:

flutter pub add flutter_fgbg

然后进行一次干净的构建以确保插件的原生代码被正确集成到应用中。否则你可能会遇到 MissingPluginException 异常。

使用内置Widget

你可以直接使用 FGBGNotifier Widget:

FGBGNotifier(
    onEvent: (event) {
        print(event); // FGBGType.foreground 或 FGBGType.background
    },
    child: ...,
)

订阅事件流

或者你可以直接消费事件流:

import 'package:flutter_fgbg/flutter_fgbg.dart';

StreamSubscription<FGBGType> subscription;

...
// 在 initState 中
subscription = FGBGEvents.instance.stream.listen((event) {
    print(event); // FGBGType.foreground 或 FGBGType.background
});

// 在 dispose 中
subscription.cancel();

注意事项

在较新的Android版本和 image_picker 库中,选择图片将会打开另一个应用程序,这会使Flutter应用程序切换到后台/前台,并且 flutter_fgbg 会报告这种情况。目前没有解决方案,因为API是按预期工作的。相关问题正在 这里 跟踪。

作为一个解决方法,你可以使用 FGBGEvents.ignoreWhile API,例如:

FGBGEvents.ignoreWhile(() async {
    await picker.pickImage(source: ImageSource.gallery);
    // 或者执行其他可能将应用程序置于后台但不希望由 flutter_fgbg 处理的操作
});

示例代码

下面是一个完整的示例代码,演示如何在应用程序中使用 flutter_fgbg 插件:

import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_fgbg/flutter_fgbg.dart';
import 'package:image_picker/image_picker.dart';
import 'package:local_auth/local_auth.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

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

class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
  final picker = ImagePicker();
  List<String> events = [];
  bool get _webOrMobile => kIsWeb || Platform.isAndroid || Platform.isIOS;
  bool get _mobile => !kIsWeb && (Platform.isAndroid || Platform.isIOS);

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    events.add(state.toString());
    setState(() {});
  }

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
  }

  @override
  Widget build(BuildContext context) {
    return FGBGNotifier(
      onEvent: (event) {
        events.add(event.toString());
        setState(() {});
      },
      child: MaterialApp(
        home: Scaffold(
          body: SafeArea(
            child: Padding(
              padding: const EdgeInsets.all(16.0),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: <Widget>[
                  const Text('All platforms:'),
                  ElevatedButton(
                    onPressed: () {
                      events.clear();
                      setState(() {});
                    },
                    child: const Text("Clear logs"),
                  ),
                  const SizedBox(height: 16),
                  const Text('Web + Mobile only:'),
                  ElevatedButton(
                    onPressed: !_webOrMobile
                        ? null
                        : () async {
                            events.add("// Opening camera");
                            setState(() {});
                            await picker.pickImage(source: ImageSource.camera);
                          },
                    child: const Text("Take Image"),
                  ),
                  ElevatedButton(
                    onPressed: !_webOrMobile
                        ? null
                        : () async {
                            events.add("// Opening gallery");
                            setState(() {});
                            await picker.pickImage(source: ImageSource.gallery);
                          },
                    child: const Text("Pick Image"),
                  ),
                  ElevatedButton(
                    onPressed: !_webOrMobile
                        ? null
                        : () async {
                            events.add(
                                "// Opening camera but ignoring events during this");
                            setState(() {});
                            FGBGEvents.ignoreWhile(() async {
                              await picker.pickImage(
                                  source: ImageSource.camera);
                            });
                          },
                    child: const Text("Take Image ignoreWhile"),
                  ),
                  ElevatedButton(
                    onPressed: !_webOrMobile
                        ? null
                        : () async {
                            events.add(
                                "// Opening gallery but ignoring events during this");
                            setState(() {});

                            FGBGEvents.ignoreWhile(() async {
                              await picker.pickImage(
                                  source: ImageSource.gallery);
                            });
                          },
                    child: const Text("Pick Image ignoreWhile"),
                  ),
                  const SizedBox(height: 16),
                  const Text('Mobile only:'),
                  ElevatedButton(
                    onPressed: !_mobile
                        ? null
                        : () async {
                            events.add("// Prompting biometric");
                            setState(() {});
                            var auth = LocalAuthentication();

                            await auth.authenticate(
                              options: const AuthenticationOptions(
                                biometricOnly: true,
                              ),
                              localizedReason: 'Test',
                            );
                          },
                    child: const Text("FaceID"),
                  ),
                  const SizedBox(height: 16),
                  const Text('Events:'),
                  Expanded(
                    child: ListView(
                      children: [for (var e in events) Text(e)],
                    ),
                  ),
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }
}

这段代码创建了一个简单的Flutter应用程序,展示了如何使用 flutter_fgbg 插件来监听应用程序的前后台状态变化,并处理不同平台上的特定操作,如拍照、选择图片和生物识别验证等。


更多关于Flutter应用前后台状态管理插件flutter_fgbg的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter应用前后台状态管理插件flutter_fgbg的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter应用中使用flutter_fgbg插件来管理前后台状态的示例代码。flutter_fgbg插件可以帮助开发者监听应用进入前台和后台的事件,从而进行相应的状态管理。

首先,确保你已经在pubspec.yaml文件中添加了flutter_fgbg依赖:

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

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

接下来,在你的Flutter应用中,你可以按照以下步骤使用flutter_fgbg插件:

  1. 导入插件

在你的Dart文件中(例如main.dart),导入flutter_fgbg插件:

import 'package:flutter_fgbg/flutter_fgbg.dart';
  1. 初始化插件

在你的应用初始化代码中(例如在MainActivityonCreate方法中,或者在你的Dart代码的入口点),初始化FlutterFgBg插件,并设置监听器:

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  FlutterFgBg.instance.initialize((String state) {
    if (state == FlutterFgBg.inForeground) {
      // 应用进入前台
      print("App entered foreground");
      // 在这里执行进入前台时需要执行的逻辑
    } else if (state == FlutterFgBg.inBackground) {
      // 应用进入后台
      print("App entered background");
      // 在这里执行进入后台时需要执行的逻辑
    }
  });
  
  runApp(MyApp());
}
  1. 处理应用状态变化

现在,你的应用已经能够监听并处理前后台状态变化了。你可以在监听器中添加你需要的逻辑,例如保存数据、停止某些后台任务等。

完整示例代码(main.dart):

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

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  FlutterFgBg.instance.initialize((String state) {
    if (state == FlutterFgBg.inForeground) {
      print("App entered foreground");
      // 例如,恢复某些后台被暂停的任务
    } else if (state == FlutterFgBg.inBackground) {
      print("App entered background");
      // 例如,保存当前状态或停止某些任务
    }
  });

  runApp(MyApp());
}

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

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter FG/BG Demo'),
      ),
      body: Center(
        child: Text('Check console for FG/BG state changes'),
      ),
    );
  }
}

这个示例展示了如何在Flutter应用中使用flutter_fgbg插件来监听和处理应用的前后台状态变化。你可以根据实际需求在监听器中添加相应的逻辑。

回到顶部