How to Implement Schedule Notification in Flutter?

46 Views Asked by At

I currently following some tutorial video and working on the local schedule notification but it did not work or showing any notification when arrived the scheduled time. Anyone can please guide me or point out which part is causing the problem, appreciate those help. Thank you.

main.dart

// ignore_for_file: unused_field, avoid_unnecessary_containers, sized_box_for_whitespace, deprecated_member_use, avoid_print
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:timezone/timezone.dart' as tz;
import 'package:timezone/data/latest.dart' as tz;

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(const MaterialApp(
    debugShowCheckedModeBanner: false,
    localizationsDelegates: [
      GlobalMaterialLocalizations.delegate,
      GlobalWidgetsLocalizations.delegate,
      GlobalCupertinoLocalizations.delegate,
    ],
    supportedLocales: [
      Locale('en', 'US'),
    ],
    home: ScheduleNotification(),
  ));
}

class ScheduleNotification extends StatefulWidget {
  const ScheduleNotification({super.key});

  @override
  State<ScheduleNotification> createState() => _ScheduleNotificationState();
}

class _ScheduleNotificationState extends State<ScheduleNotification> {
  final TextEditingController _title = TextEditingController();

  final TextEditingController _desc = TextEditingController();

  final TextEditingController _date = TextEditingController();
  final TextEditingController _time = TextEditingController();

  DateTime dateTime = DateTime.now();

  final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
      FlutterLocalNotificationsPlugin();

  @override
  void initState() {
    super.initState();
    const AndroidInitializationSettings androidInitializationSettings =
        AndroidInitializationSettings("@mipmap/ic_launcher");

    const DarwinInitializationSettings iosInitializationSettings =
        DarwinInitializationSettings();

    const InitializationSettings initializationSettings =
        InitializationSettings(
            android: androidInitializationSettings,
            iOS: iosInitializationSettings,
            macOS: null,
            linux: null);

    flutterLocalNotificationsPlugin.initialize(initializationSettings,
        onDidReceiveNotificationResponse:
            (dataYouNeedToUseWhenNotificationIsClicked) {});
  }

  showNotification() {
    if (_title.text.isEmpty || _desc.text.isEmpty) {
      return;
    }

    const AndroidNotificationDetails androidNotificationDetails =
        AndroidNotificationDetails("1", "NotifyMe", importance: Importance.max);

    const DarwinNotificationDetails darwinNotificationDetails =
        DarwinNotificationDetails(
            presentAlert: true, presentBadge: true, presentSound: true);

    const NotificationDetails notificationDetails = NotificationDetails(
        android: androidNotificationDetails,
        iOS: darwinNotificationDetails,
        macOS: null,
        linux: null);

    // flutterLocalNotificationsPlugin.show(01, _title.text, _desc.text, notificationDetails);
    tz.initializeTimeZones();
    final tz.TZDateTime scheduledAt = tz.TZDateTime.from(dateTime, tz.local);

    flutterLocalNotificationsPlugin.zonedSchedule(
        01, _title.text, _desc.text, scheduledAt, notificationDetails,
        uiLocalNotificationDateInterpretation:
            UILocalNotificationDateInterpretation.absoluteTime,
        androidAllowWhileIdle: true,
        payload: "This is the data");
    print("Schedule has set");
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Center(
      child: Container(
          // width: MediaQuery.of(context).size.width * 0.8,
          child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          TextField(
            controller: _title,
            decoration: InputDecoration(
              border: OutlineInputBorder(
                borderRadius: BorderRadius.circular(16.0),
              ),
              label: const Text("Notification Title"),
            ),
          ),
          const SizedBox(height: 16.0),
          TextField(
            controller: _desc,
            decoration: InputDecoration(
              border: OutlineInputBorder(
                borderRadius: BorderRadius.circular(16.0),
              ),
              label: const Text("Notification Description"),
            ),
          ),
          const SizedBox(height: 16.0),
          TextField(
            controller: _date,
            decoration: InputDecoration(
              border: OutlineInputBorder(
                borderRadius: BorderRadius.circular(12.0),
              ),
              suffixIcon: InkWell(
                child: const Icon(Icons.date_range),
                onTap: () async {
                  final DateTime? newlySelectedDate = await showDatePicker(
                      context: context,
                      initialDate: dateTime,
                      firstDate: DateTime.now(),
                      lastDate: DateTime(2095));
                  if (newlySelectedDate == null) {
                    return;
                  }
                  setState(() {
                    dateTime = newlySelectedDate;
                    _date.text =
                        "${dateTime.year}/${dateTime.month}/${dateTime.day}";
                  });
                },
              ),
              label: const Text("Date"),
            ),
          ),
          const SizedBox(height: 16.0),
          TextField(
            controller: _time,
            decoration: InputDecoration(
                border: OutlineInputBorder(
                  borderRadius: BorderRadius.circular(12.0),
                ),
                suffixIcon: InkWell(
                  child: const Icon(
                    Icons.timer_outlined,
                  ),
                  onTap: () async {
                    final TimeOfDay? selectedTime = await showTimePicker(
                        context: context, initialTime: TimeOfDay.now());

                    if (selectedTime == null) {
                      return;
                    }

                    _time.text =
                        "${selectedTime.hour}:${selectedTime.minute}:${selectedTime.period.toString()}";

                    DateTime newDT = DateTime(
                      dateTime.year,
                      dateTime.month,
                      dateTime.day,
                      selectedTime.hour,
                      selectedTime.minute,
                    );
                    setState(() {
                      dateTime = newDT;
                    });
                  },
                ),
                label: const Text("Time")),
          ),
          const SizedBox(height: 16.0),
          ElevatedButton(
            onPressed: showNotification,
            child: const Text("Show Notification"),
          ),
        ],
      )),
    ));
  }
}

AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" /> 
<uses-permission android:name="android.permission.USE_EXACT_ALARM" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WAKE_LOCK"/>
    <application
        android:label="schedule_notification"
        android:name="${applicationName}"
        android:icon="@mipmap/ic_launcher">
        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:launchMode="singleTop"
            android:theme="@style/LaunchTheme"
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
            android:hardwareAccelerated="true"
            android:windowSoftInputMode="adjustResize">
            <!-- Specifies an Android theme to apply to this Activity as soon as
                 the Android process has started. This theme is visible to the user
                 while the Flutter UI initializes. After that, this theme continues
                 to determine the Window background behind the Flutter UI. -->
            <meta-data
              android:name="io.flutter.embedding.android.NormalTheme"
              android:resource="@style/NormalTheme"
              />
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <!-- Don't delete the meta-data below.
             This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
        <meta-data
            android:name="flutterEmbedding"
            android:value="2" />
    </application>
</manifest>
0

There are 0 best solutions below