0

Here it is my UI

enter image description here

I successfully implemented Firebase notifications. When I add a title, description, and date, and click the button, a notification is sent from Firebase to my device. However, I want to receive a notification based on the date and time I set within the application.

notification screenshot

enter image description here

my codeUI code


  DateTime now = new DateTime.now();
  void showDatePickerNextVaccinationDate() {
    DateTime mindate = DateTime(now.year , now.month, now.day);
    DateTime maxdate = DateTime(now.year + 12, now.month, now.day);
    showCupertinoModalPopup(
        context: context,
        builder: (BuildContext builder) {
          return Container(
            height: MediaQuery.of(context).copyWith().size.height * 0.25,
            color: Colors.white,
            child: CupertinoDatePicker(
              maximumYear: now.year + 12,
              minimumYear: now.year ,
              mode: CupertinoDatePickerMode.dateAndTime,
              initialDateTime: mindate,
              onDateTimeChanged: (value) {
                if (value != nextDate) {
                  setState(() {
                    nextDate = value;
                    //calAge();
                  });
                }
              },
              maximumDate: maxdate,
              minimumDate: mindate,
            ),
          );
        });
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            TextFormField(
              controller: title,
            ),
            TextFormField(
              controller: body,
            ),
            GestureDetector(
              onTap: showDatePickerNextVaccinationDate,
              child: SizedBox(
                width: 500,
                height: 70,
                child: Container(
                  decoration: BoxDecoration(
                    border: Border.all(color: Colors.black),
                    borderRadius: BorderRadius.circular(15),
                  ),
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [
                      Padding(
                        padding: EdgeInsets.only(
                          left: 3,
                          top:20,
                          bottom: 10,
                        ),
                        child: Text(
                          nextDate == null
                              ? 'Next Vaccinated Date'
                              : DateFormat('HH MMMM dd yyyy ')
                              .format(nextDate!),
                          style: const TextStyle(
                            fontSize: 16,
                            fontWeight: FontWeight.w300,
                          ),
                        ),
                      ),
                      Icon(
                        Icons.arrow_drop_down,
                        color: Colors.grey[700],
                        size: 30.0,
                      ),
                    ],
                  ),
                ),
              ),
            ),
            GestureDetector(
              onTap: () async {
                String name = "User1";
                String titleText = title.text;
                String bodyText = body.text;
                String selectedNextDate  = nextDate.toString();
                if (name != "") {
                  DocumentSnapshot snap = await FirebaseFirestore.instance
                      .collection("UserTokens")
                      .doc(name)
                      .get();
                  String token = snap['token'];
                  print(token);
                  //call sendPushMessage
                  sendPushMessage(token, titleText, bodyText,selectedNextDate);
                }
              },
              child: Container(
                margin: EdgeInsets.all(20),
                height: 40,
                width: 200,
                decoration: BoxDecoration(
                    color: Colors.red,
                    borderRadius: BorderRadius.circular(20),
                    boxShadow: [
                      BoxShadow(
                        color: Colors.redAccent.withOpacity(0.5),
                      )
                    ]),
                child: Center(
                  child: Text("button"),
                ),
              ),
            )
          ],
        ),
      ),
    );
  }
}

function

void sendPushMessage(String token, String body, String title,String selectedNextDate) async {
    try {
      await http.post(Uri.parse('https://fcm.googleapis.com/fcm/send'),
          headers: <String, String>{
            'Content-Type': 'application/json',
            'Authorization': 'key=....',
          },
          body: jsonEncode(<String, dynamic>{
            'priority': 'high',

            //want this to when click message open that page (payload function)
            'data': <String, dynamic>{
              'click_action': 'Test_Notification',
              'status': 'done',
              'body': '$body $selectedNextDate',
              'title': title,
              "isScheduled" : "true",
              "scheduledTime" : "2023-05-17 18:44:00"

            },
            "notification": <String, dynamic>{
              "title": title,
              "body":'$body $selectedNextDate',
              "android_channel_id": "dbfood",
          "isScheduled" : "true",
          "scheduledTime" : "2023-05-17 18:44:00"
            },
            "to": token,
          }));
    } catch (e) {
      if (kDebugMode) {
        print("Error push notification");
      }
    }
  }

How I solve this ?

Dasun Dola
  • 541
  • 2
  • 16
  • 1
    *firebaser here* Calls to the FCM REST API require that you specify the FCM *server** key in your code. As its name implies, this key should only be used in server-side code, or in an otherwise trusted environment. The reason for this is that anyone who has the FCM server key can send whatever message they want to all of your users. By including this key in your Flutter app irself, a malicious user can find it and you're putting your users at risk. See https://stackoverflow.com/a/37993724 for a better solution. – Frank van Puffelen May 17 '23 at 14:36
  • 1
    Also: there is no way to schedule delivery of notifications through the FCM API. You will either need to schedule the delivery on your server itself, or schedule the display of the message once your Flutter code receives it. – Frank van Puffelen May 17 '23 at 14:37
  • Thank you for your valuable comment support that is not actual sever key that is fake by the way I removed that also. I will try that. – Dasun Dola May 17 '23 at 14:51

1 Answers1

1

Unfortunately, Firebase Cloud Messaging does not support push notifications scheduling. However, you can schedule notifications locally with flutter_local_notifications library. You can send a data message from Firebase then when your app receives it, you use the local notifications package to schedule the notification based on scheduledTime.

Tayo.dev
  • 1,546
  • 3
  • 21
  • 31
  • But my doubt is, Android users have the ability to clear the application cache or if a user deletes the app and then redownloads it, the cached data will be cleared, and any scheduled reminder notifications might be lost. But when adding data save in Cloud Firestore. – Dasun Dola May 17 '23 at 14:59
  • When I was typing my previous comments, I got an idea to solve that problem. The idea is to save the new assessment data in a separate collection as duplicate data, while the original data is saved in the usual way, such as in the user's subcollection. If a user deletes or clears the cache and then logs in to the application, the login function can fetch the duplicate reminders from the relevant user's separate collection. These fetched reminders can then be saved as local notifications within the application. – Dasun Dola May 17 '23 at 15:08
  • Actually, I considered using duplicate data saved in a separate collection. However, I realized that it may not be possible to fetch all the subcollections of the third step with just the knowledge of the first collection ID. Let me explain using the database hierarchy. In the user collection, there are multiple users, and each user has multiple subjects. Additionally, those subjects can have multiple assessments. – Dasun Dola May 17 '23 at 15:19
  • Is this idea a good solution to this problem? Based on your knowledge, do you have any other ideas that might be more effective? @Tayo.dev – Dasun Dola May 17 '23 at 15:20
  • also , do you have any other ideas that might be more effective? @Frank van Puffelen – Dasun Dola May 17 '23 at 15:22
  • 1
    @DasunDola I believe you can managed a local db that stores the ids of local notifications that have been scheduled. When the user's phone cache or data is cleared these data get cleared too. Then when you fetch active assessments on Firestore, you can correlate them with the local data and see if there's a schedule for each otherwise your create a scheduled notification. – Tayo.dev May 17 '23 at 16:18