Flutter 本地通知无法在后台运行?

问题描述 投票:0回答:5

我正在使用 flutter 本地通知在我的应用程序中显示日程通知。但不幸的是,当应用程序处于终止状态时,它无法工作。

这是我的代码:

class Notifications {
static final FlutterLocalNotificationsPlugin _notifications =
  FlutterLocalNotificationsPlugin();

static Future<NotificationDetails> _notificationDetails() async {
return const NotificationDetails(
    android: AndroidNotificationDetails(
      'weekly notification channel id',
      'weekly notification channel name',
      channelDescription: 'weekly notification description',
      playSound: true,
      sound: RawResourceAndroidNotificationSound('azan1'),
      importance: Importance.high,
    ),
    iOS: IOSNotificationDetails(sound: 'azan1.mp3', presentSound: true));
}

static void init() async {
tz.initializeTimeZones();
const AndroidInitializationSettings android =
    AndroidInitializationSettings('@mipmap/ic_launcher');
const IOSInitializationSettings iOS = IOSInitializationSettings();
InitializationSettings settings =
    const InitializationSettings(android: android, iOS: iOS);
await _notifications.initialize(settings);
final String locationName = await FlutterNativeTimezone.getLocalTimezone();
tz.setLocalLocation(tz.getLocation(locationName));
}

static void showScheduledNotification(
int id, {
required DateTime scheduledDate,
String? title,
String? body,
String? payload,
}) async {
await _notifications.zonedSchedule(
  id,
  'Azan Time',
  '$body Prayer Time',
  _scheduleDaily(
      Time(scheduledDate.hour, scheduledDate.minute, scheduledDate.second)),
  await _notificationDetails(),
  androidAllowWhileIdle: true,
  uiLocalNotificationDateInterpretation:
      UILocalNotificationDateInterpretation.absoluteTime,
  matchDateTimeComponents: DateTimeComponents.time,
  payload: payload,
 );
 }

static tz.TZDateTime _scheduleDaily(Time time) {
tz.TZDateTime now = tz.TZDateTime.now(tz.local);
tz.TZDateTime schdeuledDate = tz.TZDateTime(tz.local, now.year, now.month,
    now.day, time.hour, time.minute, time.second);
return schdeuledDate.isBefore(now)
    ? schdeuledDate.add(const Duration(days:1))
    : schdeuledDate;
}

static Future<void> cancelNotification(int id) async {
await _notifications.cancel(id);
}

static Future<void> cancelAllNotifications() async {
await _notifications.cancelAll();
 }
 }

我还在 Android.xml 文件中添加了所有属性。 但它仍然不起作用,如果有人知道这个问题的解决方案,请回答这个问题。

flutter dart localnotification flutter-notification
5个回答
3
投票

本地通知可能有点棘手。查看

flutter_local_notifications
自述文件:

一些 Android OEM 拥有自己定制的 Android 操作系统,可以阻止应用程序在后台运行。因此,当应用程序在某些设备(例如小米、华为)上处于后台时,预定通知可能不起作用。如果您遇到这样的问题,那么这就是原因。由于这是操作系统施加的限制,因此插件无法解决此问题。某些设备可能具有允许用户控制哪些应用程序在后台运行的设置。这些步骤可能会有所不同,但考虑到这是手机本身的设置,仍然取决于应用程序的用户来执行。

据报道,三星的 Android 实施规定最多可通过 Alarm Manager API 安排 500 个警报,超过限制时可能会发生异常。

来源: https://pub.dev/packages/flutter_local_notifications#scheduled-android-notifications


2
投票

根据我的理解(可能不正确),在后台工作终止是两个完全不同的事情。

如果应用程序被终止,即被迫退出并完全死亡,则无法显示本地通知,应使用 firebase 推送通知。

有关 AppLifecycleState 的更多信息。

另外,如何检查Flutter应用程序是否在前台?


1
投票

如果您能提供您的主要功能,那将会很有帮助。我将为您提供一个有关如何创建任何计划通知的一般示例。

import 'package:flutter_native_timezone/flutter_native_timezone.dart';
import 'package:rxdart/rxdart.dart';
import 'package:timezone/data/latest.dart' as tz;
import 'package:timezone/timezone.dart' as tz;
import 'package:flutter_local_notifications/flutter_local_notifications.dart';

class NotificationApi {
  static final _notification = FlutterLocalNotificationsPlugin();
  static final onNotifications = BehaviorSubject<String?>();

  static Future _notificationDetails() async {
    return const NotificationDetails(
      android: AndroidNotificationDetails(
        'channel id',
        'channel name',
        channelDescription: 'Update users on new deal',
        importance: Importance.max,
        enableLights: true,
      ),
      iOS: IOSNotificationDetails(),
    );
  }

  static Future init({bool initScheduled = true}) async {
    const android = AndroidInitializationSettings('@drawable/ic_notcion');
    const iOS = IOSInitializationSettings();
    const settings = InitializationSettings(android: android, iOS: iOS);

    /// when app is closed
    final details = await _notification.getNotificationAppLaunchDetails();
    if (details != null && details.didNotificationLaunchApp) {
      onNotifications.add(details.payload);
    }
    await _notification.initialize(
      settings,
      onSelectNotification: (payload) async {
        onNotifications.add(payload);
      },
    );

    if(initScheduled){
      tz.initializeTimeZones();
      final locationName = await FlutterNativeTimezone.getLocalTimezone();
      tz.setLocalLocation(tz.getLocation(locationName));
    }
  }

  static tz.TZDateTime _scheduledDaily(Time time) {
    final now = tz.TZDateTime.now(tz.local);
    final scheduledDate = tz.TZDateTime(tz.local, now.year, now.month, now.day,
        time.hour);

    return scheduledDate.isBefore(now)
        ? scheduledDate.add(const Duration(days: 1))
        : scheduledDate;
  }

  static tz.TZDateTime _scheduleWeekly(Time time, {required List<int> days}) {
    tz.TZDateTime scheduledDate = _scheduledDaily(time);

    while (!days.contains(scheduledDate.weekday)) {
      scheduledDate = scheduledDate.add(const Duration(days: 1));
    }
    return scheduledDate;
  }

  static Future showWeeklyScheduledNotification({
    int id = 8,
    String? title,
    String? body,
    String? payload,
    required DateTime scheduledDate,
  }) async =>
      _notification.zonedSchedule(
        id,
        title,
        body,
        _scheduleWeekly(const Time(17), days: [
          DateTime.tuesday,
          DateTime.friday,
          DateTime.saturday,
          DateTime.sunday,
        ]),
        // tz.TZDateTime.from(scheduledDate, tz.local),
        await _notificationDetails(),
        payload: payload,
        androidAllowWhileIdle: true,
        uiLocalNotificationDateInterpretation:
            UILocalNotificationDateInterpretation.absoluteTime,
        matchDateTimeComponents: DateTimeComponents.dayOfWeekAndTime,
      );

  static void cancelAll() => _notification.cancelAll();
}

在main函数中,初始化NotificationApi如下:

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
    //__________________________________Notification and Time Zone
  tz.initializeTimeZones();
  await NotificationApi.init();
  await NotificationApi.init(initScheduled: true);
}
 

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

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

class _MyAppState extends State<MyApp> {
  // This widget is the root of your application.

  ///_____________________Init state initialising notifications
  @override
  void initState() {
    loadAllNotifications;
    super.initState();
  }

  loadAllNotifications() {
    NotificationApi.showWeeklyScheduledNotification(
        title: '🏆 New Deals Available 🏆',
        body: '✨ Don\'t miss your opportunity to win BIG 💰💰',
        scheduledDate: DateTime.now().add(const Duration(seconds: 12)));
    NotificationApi.init(initScheduled: true);
    listenNotifications();
  }


  //___________________________Listen to Notifications
  void listenNotifications() =>
      NotificationApi.onNotifications.stream.listen(onClickedNotification);

  //__________________________On Notification Clicked
  void onClickedNotification(String? payload) => Navigator.of(context).push(
      MaterialPageRoute(builder: (context) => AppWrapper(updates: updates)));

  //________________________________________Widget Build
  @override
  Widget build(BuildContext context) => MaterialApp(
            debugShowCheckedModeBanner: false,
            title: 'Alpha Deals',
            home: MyHomePage()
          
      );
}

0
投票

在你的Application.java中,如果这部分不起作用,你可以转义它来运行应用程序。

private void createNotificationChannels() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channelHigh = new NotificationChannel(
                    CHANNEL_HIGH,
                    "Notificación Importante",
                    NotificationManager.IMPORTANCE_HIGH
            );

            channelHigh.setDescription("Canal Alto");

            NotificationManager manager = getSystemService(NotificationManager.class);
            manager.createNotificationChannel(channelHigh);

        }
    }

检查清单文件,不要忘记添加

  <meta-data
    android:name="com.google.firebase.messaging.default_notification_channel_id"
    android:value="default"/>

了解更多请查看此链接


0
投票

我认为可以在后台使用它之前再次初始化它,因为它使用单独的环境

© www.soinside.com 2019 - 2024. All rights reserved.