13

I am using flutter local notification to display schedule notification in my app. But unfortunately it is not working when app is in terminated state.

Here is my code:

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();
 }
 }

I have also added all properties in Android.xml file. But still it is not working if anybody know the solution of this problem kindly answer this question.

Zilaid
  • 464
  • 6
  • 22

4 Answers4

1

Local notifications might be a bit tricky. Look at the flutter_local_notifications README file:

Some Android OEMs have their own customised Android OS that can prevent applications from running in the background. Consequently, scheduled notifications may not work when the application is in the background on certain devices (e.g. by Xiaomi, Huawei). If you experience problems like this then this would be the reason why. As it's a restriction imposed by the OS, this is not something that can be resolved by the plugin. Some devices may have setting that lets users control which applications run in the background. The steps for these can vary but it is still up to the users of your application to do given it's a setting on the phone itself.

It has been reported that Samsung's implementation of Android has imposed a maximum of 500 alarms that can be scheduled via the Alarm Manager API and exceptions can occur when going over the limit.

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

bartektartanus
  • 15,284
  • 6
  • 74
  • 102
1

If you could provide your main function, it would have been helpful. I'll give you a general example of how to create any scheduled notification.

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();
}

On the main function, init the NotificationApi as follows:

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()
          
      );
}
dev.bojack
  • 753
  • 5
  • 9
  • Does the weekly scheduling for multiple days work for you? I have the code exactly like you, but it always shows the notification only on the first day specified in the list (DateTime.tuesday in your case). The other days (DateTime.friday, DateTime.saturday, DateTime.sunday in your case) get ignored. – Sebb Feb 28 '23 at 17:09
  • Make sure the notification does not cancel, remove the code to cancel the notifications "static void cancelAll() => _notification.cancelAll();" and try again. – dev.bojack Feb 28 '23 at 22:52
  • I did, still no luck. The _scheduleWeekly() Method does not seem to work for more than 1 day. Does it work for you? – Sebb Mar 01 '23 at 07:58
  • Yes. Mine works perfectly. Follow the instructions in this video. https://www.youtube.com/watch?v=bRy5dmts3X8&t=601s. If you find the error in the code, I will appreciate your response. – dev.bojack Mar 02 '23 at 20:45
  • The function in the video only returns one DateTime object, which is customized based on the first day in the list that you provide with the function. But still, it is only one DateTime object, so it will only schedule a notification for this specific day. – Sebb Mar 23 '23 at 09:19
1

According to my understanding which may be incorrect, working in the background and terminated are two completely different things.

If the app is terminated i.e. forced to quit and completely dead, there is no way to show local notifications, firebase push notifications should be used instead.

More info about AppLifecycleState.

Also, How do I check if the Flutter application is in the foreground or not?

Yuriy N.
  • 4,936
  • 2
  • 38
  • 31
0

In your Application.java if this part not work you can escape it to run the app .

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);

        }
    }

Check the Manifest File and do not forget to add

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

For More Check This Link