For my voluntary music festival app project (Festival Holledau iOS & Android), I need notifications.

I don’t want to built up a backend with registrations and privacy overhead. So I decided to implement on device notifications. There are not much out there. Shiny came later around, but I was finished with my implementation.
I also built up the permission request, now I would use Xamarin.Essentials.

Here is my example implementation which uses the methods CheckIfPushIsAllowed() and SetPushesAsync() on each platform. For Android we have to call LocalNotification.Setup()in the MainActivity.cs file.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Android.App;
using Android.Content;
using Android.Content.Res;
using Android.OS;
using Android.Runtime;
using Android.Support.V4.App;
using Android.Support.V4.Content;
using FestivalHolledauApp.Droid;
using FestivalHolledauApp.Models;
using Java.Util;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;

[assembly: Dependency(typeof(LocalNotification))]
namespace FestivalHolledauApp.Droid
{
    public class LocalNotification : ILocalNotification
    {
        private static Context Context;
        public const string CHANNEL_ID = "1";

        public static void Setup(Context context)
        {
            Context = context;
            var channelName = "Festival Holledau";            
            var channel = new NotificationChannel(CHANNEL_ID, channelName, NotificationImportance.Default);

            NotificationManager notificationManager = context.GetSystemService(Context.NotificationService) as NotificationManager;
            notificationManager.CreateNotificationChannel(channel);
        }

        public async Task SetPushesAsync(IEnumerable<Band> bands)
        {
            foreach (var band in bands)
            {
                AlarmManager alarmManager = Context.GetSystemService(Context.AlarmService).JavaCast<AlarmManager>();
                var timeToDisplay = band.DateTime.ToString("HH:mm");
                var message = $"Beginn {timeToDisplay}";

                var alarmIntent = new Intent(Context, typeof(AlarmReceiver));                                
                alarmIntent.PutExtra("id", band.Id);
                alarmIntent.PutExtra("title", band.Name);
                alarmIntent.PutExtra("message", message);
                
                DateTime dateTime;
#if DEBUG
                dateTime = DateTime.Now + new TimeSpan(0, 0, 3);
#else
                int minutesFromSettings = (int)AppSettings.ViewModel.NotificationMinutesBevorBand;
                dateTime = band.DateTime - new TimeSpan(0, minutesFromSettings, 0);
#endif
                DateTimeOffset dateOffsetValue = DateTimeOffset.Parse(dateTime.ToString());
                long millisecondsToBegin = dateOffsetValue.ToUnixTimeMilliseconds();
                int bandId = Convert.ToInt32(band.Id);
                PendingIntent pending = PendingIntent.GetBroadcast(Context, bandId, alarmIntent, PendingIntentFlags.UpdateCurrent);

                // Add push
                if (band.IsFavorite && dateTime > DateTime.Now  && band.DateTime.Month != 1 && band.DateTime.Day != 1)
                {
                    alarmManager.Set(AlarmType.RtcWakeup, millisecondsToBegin, pending);
                }
                else
                {
                    pending.Cancel();
                }
            }
        }

        public bool IsPushAllowed()
        {
            // not needed on Android
            return true;
        }

        public void RequestPermission()
        {
            // not needed on Android
        }
    }

    [BroadcastReceiver]
    public class AlarmReceiver : BroadcastReceiver
    {
        public override void OnReceive(Context context, Intent intent)
        {
            var title = intent.GetStringExtra("title");
            var message = intent.GetStringExtra("message");
            var idString = intent.GetStringExtra("id");
            var id = Convert.ToInt32(idString);

            Intent resultIntent = new Intent(context, typeof(MainActivity));
            resultIntent.SetFlags(ActivityFlags.NewTask | ActivityFlags.ClearTask);

            const int pendingIntentId = 0;
            PendingIntent pendingIntent = PendingIntent.GetActivity(context, pendingIntentId, resultIntent, PendingIntentFlags.OneShot);

            var color = Constants.ColorPrimary.ToAndroid().ToArgb();
            NotificationCompat.Builder builder = new NotificationCompat.Builder(context, LocalNotification.CHANNEL_ID)
                .SetContentTitle(title)
                .SetContentText(message)
                .SetDefaults((int)(NotificationDefaults.Sound | NotificationDefaults.Vibrate))
                .SetSmallIcon(Resource.Mipmap.icon_notification)
                .SetColor(color)
                .SetContentIntent(pendingIntent)
                .SetPriority((int)NotificationPriority.High);

            NotificationManager notificationManager = context.GetSystemService(Context.NotificationService) as NotificationManager;
            Notification notification = builder.Build();
            notificationManager.Notify(id, notification);

        }
    }

}

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using FestivalHolledauApp.iOS;
using FestivalHolledauApp.Models;
using Foundation;
using UIKit;
using UserNotifications;
using Xamarin.Forms;

[assembly: Dependency(typeof(LocalNotification))]
namespace FestivalHolledauApp.iOS
{
    public class LocalNotification : ILocalNotification
    {
        private bool _alertsAllowed;

        public LocalNotification()
        {
            UNUserNotificationCenter.Current.GetNotificationSettings(CheckIfPushIsAllowed);            
        }
       
        void CheckIfPushIsAllowed(UNNotificationSettings settings)
        {
            _alertsAllowed = settings.AlertSetting == UNNotificationSetting.Enabled;
        }

        public bool IsPushAllowed()
        {
            return _alertsAllowed;
        }

        public void RequestPermissio