当在前台或后台接收到 Firebase 通知时,展示 Flutter 本地通知。

3
我正在尝试在应用程序的后台、前台和终止状态下接收 Firebase 通知时显示 Flutter 本地通知。我正在尝试使用 Work Manager 包来解决这个问题,在 Android 上它像魔法一样工作。它可以在前台、后台和终止状态下正常工作,但是在 iOS 设备上却无法正常工作。如果我尝试执行未在 Info.plist 和 appDelegate 中注册的任务,它会给我一个错误,但在注册之后没有执行我的代码(没有错误)。我想象我的任务已经注册了,但 iOS 没有执行它的某些原因。如果有人做过类似的事情,请提供一些示例或者关于我做错了什么的思路吗?
我正在尝试使用 Work Manager 和 Flutter 本地通知来解决这个问题。

如果您按照此指示https://firebase.flutter.dev/docs/messaging/apple-integration#configuring-your-app进行操作,默认情况下,在iOS上应该可以正常工作,无需使用`workmanager`或`local notification`。 - pmatatias
感谢您的评论。正如您所提到的,通知是在没有本地通知的情况下显示的,但问题在于我需要使用本地通知,因为我正在向我的通知添加操作按钮,并在按下该按钮后向服务器发出一些请求。 - Karen Ghazaryan
2个回答

3
我曾花费数周的时间来解决这个问题,直到我成功让我的iOS应用程序在任何状态下都能收到通知。
首先,您必须在Xcode中勾选“后台获取”和“后台处理”模式。这些可以在签名和功能下找到。

enter image description here

接下来,您必须在AppDelegate.swift中注册您的任务并为您的应用程序提供通知功能。
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    GeneratedPluginRegistrant.register(with: self)
    UNUserNotificationCenter.current().delegate = self

    WorkmanagerPlugin.setPluginRegistrantCallback { registry in
      // Registry, in this case is the FlutterEngine that is created in Workmanager's
      // performFetchWithCompletionHandler or BGAppRefreshTask.
      // This will make other plugins available during a background operation.
      GeneratedPluginRegistrant.register(with: registry)
    }

    // you will need to duplicate the line below for each identifier
    WorkmanagerPlugin.registerTask(withIdentifier: "your.task.identifier")

    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }

  override func userNotificationCenter(
      _ center: UNUserNotificationCenter,
      willPresent notification: UNNotification,
      withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        completionHandler(.alert) // shows banner even if app is in foreground
    }

}

您还需要在 info.plist 中注册您的任务,如下所示:
    <key>BGTaskSchedulerPermittedIdentifiers</key>
    <array>
        <string>your.task.identifier/string>
    </array>
    <key>UIBackgroundModes</key>
    <array>
        <string>fetch</string>
        <string>processing</string>
    </array>

registerPeriodicTask在iOS上不起作用,因此您应该使用flutter_local_notifications的periodicallyShow函数。

为了参考,我提供了我的代码片段,展示了我如何使用workmanager和flutter_local_notifications;

void registerWorkmanagerTask() async {
  try {
    await Workmanager().registerOneOffTask(
      AppConstants.notifyReviewTask,
      AppConstants.notifyReviewTask,
      initialDelay: Duration(hours: 4),
      existingWorkPolicy: ExistingWorkPolicy.replace,
      backoffPolicy: BackoffPolicy.linear,
    );
  } catch (e) {
    print("exception caught $e");
  }
}

@pragma('vm:entry-point')
void callbackDispatcher() {
  Workmanager().executeTask((taskName, _) async {
    try {
      await NotificaitonService().setup();
      if (taskName == AppConstants.notifyReviewTask)
        await NotificaitonService().showNotification(
          body: 'items are ready to be reviewed',
          notificationId: AppConstants.recallNotificationId,
          channel: AppConstants.recallChannel,
          title: 'Time to review',
        );
      return Future.value(true);
    } catch (e) {
      print("exception caught $e");
    }
  });
}

请记住,iOS设备可以因多种原因(例如低电量)决定延迟运行后台工作管理器任务。此外,通知不会在iOS模拟器中显示。


AppConstants.notifyReviewTask是您在info.plist和AppDelegate中添加的任务标识符吗? - Karen Ghazaryan
是的,没错 - Firas AT

0

如果你愿意,你可以使用flutter_local_notification来实现这个功能。它更简单、更紧凑。

前提条件:

有以下的软件包设置:
firebase_core
firebase_messaging 
flutter_local_notifications

在后台和终止状态下的通知由flutter应用程序处理,使用默认的通知服务。
前台通知应该被创建,这里我们使用flutter_local_notification监听fcm流来创建通知。

完整代码:

import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:hello/notification_helper.dart';

Future<void> _firebaseMessagingBackgroundHandler(message) async {
  await Firebase.initializeApp();
  print('Handling a background message ${message.messageId}');
}

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  final fcmToken = await FirebaseMessaging.instance.getToken();
  debugPrint(fcmToken);
  FirebaseMessaging messaging = FirebaseMessaging.instance;

  NotificationSettings settings = await messaging.requestPermission(
    alert: true,
    announcement: false,
    badge: true,
    carPlay: false,
    criticalAlert: false,
    provisional: false,
    sound: true,
  );

  if (settings.authorizationStatus == AuthorizationStatus.authorized) {
    print('User granted permission');
  } else if (settings.authorizationStatus == AuthorizationStatus.provisional) {
    print('User granted provisional permission');
  } else {
    print('User declined or has not accepted permission');
  }
  FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
  runApp(const MyApp());
}

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

  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(),
    );
  }
}

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

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

class _MyHomePageState extends State<MyHomePage> {
  @override
  void initState() {
    LocalNotification.initialize();
    FirebaseMessaging.onMessage.listen((RemoteMessage message) {
      LocalNotification.showNotification(message);
    });
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Center(
      child: Text("Hello"),
    ));
  }
}

notification_helper.dart// 专门处理前台通知的类

import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';

class LocalNotification {
  static final FlutterLocalNotificationsPlugin _notiPlugin =
      FlutterLocalNotificationsPlugin();

  static void initialize() {
    final InitializationSettings initialSettings = InitializationSettings(
      android: AndroidInitializationSettings(
        '@mipmap/ic_launcher',
      ),
    );
    _notiPlugin.initialize(initialSettings,
        onDidReceiveNotificationResponse: (NotificationResponse details) {
      print('onDidReceiveNotificationResponse Function');
      print(details.payload);
      print(details.payload != null);
    });
  }

  static void showNotification(RemoteMessage message) {
    final NotificationDetails notiDetails = NotificationDetails(
      android: AndroidNotificationDetails(
        'com.example.push_notification',
        'push_notification',
        importance: Importance.max,
        priority: Priority.high,
      ),
    );
    _notiPlugin.show(
      DateTime.now().microsecond,
      message.notification!.title,
      message.notification!.body,
      notiDetails,
      payload: message.data.toString(),
    );
  }
}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接