Flutter Local Notifications 在每次热重启时运行回调函数

Flutter Local Notifications runs the Callback function on every hot restart

我目前正在 Flutter 中开发 Habit Tracker 应用程序。我想在每天晚上 11 点向用户发送通知,告知他们当天还剩多少习惯(如果有的话)

我的问题:回调函数在我每次热重启应用程序时运行,或者在设备未连接的情况下,它在我每次关闭应用程序并打开时运行再次。这种情况一直持续到一天结束(12:00 AM)。解决这个问题的方法是什么?如何让它每天只发送一次通知。这感觉像是一个简单的修复,但我不确定我做错了什么。

我的代码:

final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();

void scheduleNotification() async
{
  print("scheduleNotification() function Ran");
  var scheduledNotificationDateTime = DateTime(DateTime.now().year, DateTime.now().month, DateTime.now().day, 23, 00, 00);

  var androidPlatformChannelSpecifics = AndroidNotificationDetails(
    'habit_notif',
    'habit_notif',
    channelDescription: 'Channel for Habit notification',
    icon: 'applogocircle2',
    largeIcon: DrawableResourceAndroidBitmap('applogoyellowsquare'),
  );

  var iOSPlatformChannelSpecifics = IOSNotificationDetails(
      presentAlert: true,
      presentBadge: true,
      presentSound: true
  );
  var platformChannelSpecifics = NotificationDetails(
      android: androidPlatformChannelSpecifics,
      iOS: iOSPlatformChannelSpecifics
  );

  List<Map<String, dynamic>> queryRows = await DatabaseHelper.instance.queryAllValues();

  int completed = queryRows[0]["todayCompleted"];
  int total = queryRows[0]["todayTotal"];

  if(completed != total)
  {
    await flutterLocalNotificationsPlugin.schedule(
      0,
      'You haven\'t completed all your habits for today!',
      "You have ${total-completed} habits left",
      scheduledNotificationDateTime,
      platformChannelSpecifics,
      androidAllowWhileIdle: true,
    );
  }
}

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await UserSimplePreferences.init();
  runApp(const MyApp());

  WidgetsFlutterBinding.ensureInitialized();

  var initializationSettingsAndroid = AndroidInitializationSettings('applogo');
  var initializationSettingsIOS = IOSInitializationSettings(
    requestAlertPermission: true,
    requestBadgePermission: true,
    requestSoundPermission: true,
    onDidReceiveLocalNotification: (int id, String? title, String? body, String? payload) async {}
  );

  var initializationSettings = InitializationSettings(
      android: initializationSettingsAndroid,
      iOS: initializationSettingsIOS
  );

  await flutterLocalNotificationsPlugin.initialize(
      initializationSettings,
      onSelectNotification: (String? payload) async {
        if (payload != null) {
          debugPrint('Notification payload: ' + payload);
        }
      }
  );

  scheduleNotification();
  );
}

@祖海布 首先,我的回答是理论上的,因为我没有看到你的项目,但我希望你能理解,我正在分享一个简单而有效的技术,同时处理通知用户,忘记 username/password,等等

让我解释一下我在这种情况下所做的工作,首先在table(您可能使用数据库来存储用户数据),这里我将添加一个列用于user table 我们称它为“isNotified”int 数据类型和“notifiedAt”,它是一种 DateTime 数据类型,nextNotifiedAt 也是一种 DateTime 数据类型,它存储下一个 24H 值,如下所示:

before:
isNotified = 0
notifiedAt = null
nextNotifiedAt = null

after notified:
isNotified = 1
notifiedAt = 2/12/2022 11:00PM
nextNotifiedAt = 3/12/2022 11:00PM

现在,当需要通知用户时,您将从数据库中获取用户信息、用户名以及 he/she 需要执行的任务数量...此处:

List<Map<String, dynamic>> queryRows = await DatabaseHelper.instance.queryAllValues();

int completed = queryRows[0]["todayCompleted"];
int total = queryRows[0]["todayTotal"]

你必须检索那 3 列你也会得到“isNotified”和“notifiedAt” 对于用户“Awat”=> isNotified = 0 和 notifiedAt = NULL 意味着我还没有收到通知, 当您第一次向我发送通知时:

  if(completed != total){
    .....
    // IS it my first time you notifiy me?
    if (isNotified == 0){
     DO UPDATE isNotified = 1 and notifiedAt = CURRENT DATETIME (in mysql use getdate());
     // update tbl_user set isNotified = 1, notifiedAt = getdate() where user_id = X
    }else{
     // at anytime you have notified me, this is a new day..
     if (notifiedAt > nextNotifiedAt){
       // DO UPDATE
     }

    }

  }

这样做你只发送 1 次,你也可以在你通知用户完成任务时存储...

不要在此处使用本地日期时间:

  var scheduledNotificationDateTime = DateTime(DateTime.now().year, DateTime.now().month, DateTime.now().day, 23, 00, 00);

你知道用户可以手动更改他们的日期时间,所以从服务器(你的数据库服务器)获取日期时间,然后在当前用户的日期时间和你的数据库服务器的日期时间之间进行区分

var dbDateTime = getDateTimeFromServer()
var localDateTime = DateTime(...)

如果用户从 his/her 手机更改了日期和时间,您的两个值都存储在数据库中,没有人可以访问这些值,notifiedAt = 2/12/2022 11:00 PM nextNotifiedAt = 3/12/2022 11:00 下午

希望你重构你的代码并实现它,我也很抱歉大部分都是理论。