Xamarin Forms Schedule notifications

Gabriele Conti 21 Reputation points
2021-06-04T08:43:19.08+00:00

Hello everyone,

I am new to Xamarin forms, I need to add to my app a functionality so that the user can schedule reminders.
For example: Send a notification every Monday and Friday at 5 pm.

I have tried to use Local notifications with this library https://github.com/shinyorg/shiny but I am not happy with the result,
the main problem is that if I plan a notification in 3 hours, and the phone is restarted before that time, the notification never arrives.

"await ScheduleLocalNotification(DateTimeOffset.UtcNow.AddMinutes(180));"

Also, handling the schedule with a simple delay doesn't help if you need to plan the same reminder for multiple weeks.

I was wondering if push notifications are needed to achieve this behaviour, or what is the best practice to achieve something like this in general.

Thank you

Xamarin
Xamarin
A Microsoft open-source app platform for building Android and iOS apps with .NET and C#.
5,368 questions
0 comments No comments
{count} votes

Accepted answer
  1. JessieZhang-MSFT 7,711 Reputation points Microsoft Vendor
    2021-06-07T07:58:02.473+00:00

    Hello,

    Welcome to our Microsoft Q&A platform!

    You can use DependencyService to achieve this.

    You can refer to the following code:

    1.Create an interface ILocalNotificationService( which has methods declaration of LocalNotification and Cancel).

    public interface ILocalNotificationService      
    {      
        void LocalNotification(string title, string body, int id, DateTime notifyTime);      
        void Cancel(int id);      
    }  
    

    2.Create class LocalNotification with Title, Body, ID, IconId and NotifyTime. It will be useful to pass a local notification data to BroadcastReceiver receiver for repeating in Android.

    public class LocalNotification{      
    
        public string Title { get; set; }      
    
        public string Body { get; set; }      
    
        public int Id { get; set; }      
    
        public int IconId { get; set; }      
    
        public DateTime NotifyTime { get; set; }      
    }    
    

    3.In Xamarin.Android

    Create class LocalNotificationService and we need to implement LocalNotification and Cancel methods like below. In this, we have created BroadcastReceiver for repeating notification. In Android, we are using AlarmManger for repeating location notifications.

    public class LocalNotificationService : ILocalNotificationService      
    {      
        int _notificationIconId { get; set; }      
        readonly DateTime _jan1st1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);      
        internal string _randomNumber;      
    
        public void LocalNotification(string title, string body, int id, DateTime notifyTime){      
    
            //long repeateDay = 1000 * 60 * 60 * 24;      
            long repeateForMinute = 60000; // In milliseconds     
            long totalMilliSeconds = (long)(notifyTime.ToUniversalTime() - _jan1st1970).TotalMilliseconds;      
            if (totalMilliSeconds < JavaSystem.CurrentTimeMillis()){      
                totalMilliSeconds = totalMilliSeconds + repeateForMinute;      
            }      
    
            var intent = CreateIntent(id);      
            var localNotification = new LocalNotification();      
            localNotification.Title = title;      
            localNotification.Body = body;      
            localNotification.Id = id;      
            localNotification.NotifyTime = notifyTime;      
    
            if (_notificationIconId != 0){      
                localNotification.IconId = _notificationIconId;      
            }      
            else{      
                localNotification.IconId = Resource.Drawable.notificationgrey;      
            }      
    
            var serializedNotification = SerializeNotification(localNotification);      
            intent.PutExtra(ScheduledAlarmHandler.LocalNotificationKey, serializedNotification);      
    
            Random generator = new Random();        
            _randomNumber = generator.Next(100000, 999999).ToString("D6");       
    
            var pendingIntent = PendingIntent.GetBroadcast(Application.Context, Convert.ToInt32(_randomNumber), intent, PendingIntentFlags.Immutable);      
            var alarmManager = GetAlarmManager();      
            alarmManager.SetRepeating(AlarmType.RtcWakeup, totalMilliSeconds, repeateForMinute, pendingIntent);      
        }      
    
        public void Cancel(int id){      
    
            var intent = CreateIntent(id);      
            var pendingIntent = PendingIntent.GetBroadcast(Application.Context, Convert.ToInt32(_randomNumber), intent, PendingIntentFlags.Immutable);      
            var alarmManager = GetAlarmManager();      
            alarmManager.Cancel(pendingIntent);      
            var notificationManager = NotificationManagerCompat.From(Application.Context);      
            notificationManager.CancelAll();      
            notificationManager.Cancel(id);      
        }      
    
        public static Intent GetLauncherActivity(){      
    
            var packageName = Application.Context.PackageName;      
            return Application.Context.PackageManager.GetLaunchIntentForPackage(packageName);      
        }      
    
    
        private Intent CreateIntent(int id){      
    
            return new Intent(Application.Context, typeof(ScheduledAlarmHandler))      
                .SetAction("LocalNotifierIntent" + id);      
        }      
    
        private AlarmManager GetAlarmManager(){      
    
            var alarmManager = Application.Context.GetSystemService(Context.AlarmService) as AlarmManager;      
            return alarmManager;      
        }      
    
        private string SerializeNotification(LocalNotification notification){      
    
            var xmlSerializer = new XmlSerializer(notification.GetType());      
    
            using (var stringWriter = new StringWriter()){      
                xmlSerializer.Serialize(stringWriter, notification);      
                return stringWriter.ToString();      
            }      
        }      
    }      
    
    [BroadcastReceiver(Enabled = true, Label = "Local Notifications Broadcast Receiver")]      
    public class ScheduledAlarmHandler : BroadcastReceiver{      
    
        public const string LocalNotificationKey = "LocalNotification";      
    
        public override void OnReceive(Context context, Intent intent){      
            var extra = intent.GetStringExtra(LocalNotificationKey);      
            var notification = DeserializeNotification(extra);      
            //Generating notification      
            var builder = new NotificationCompat.Builder(Application.Context)      
                .SetContentTitle(notification.Title)      
                .SetContentText(notification.Body)      
                .SetSmallIcon(notification.IconId)      
                .SetSound(RingtoneManager.GetDefaultUri(RingtoneType.Ringtone))      
                .SetAutoCancel(true);      
    
            var resultIntent = LocalNotificationService.GetLauncherActivity();      
            resultIntent.SetFlags(ActivityFlags.NewTask | ActivityFlags.ClearTask);      
            var stackBuilder = Android.Support.V4.App.TaskStackBuilder.Create(Application.Context);      
            stackBuilder.AddNextIntent(resultIntent);      
    
            Random random = new Random();      
            int randomNumber = random.Next(9999 - 1000) + 1000;       
    
            var resultPendingIntent =      
                stackBuilder.GetPendingIntent(randomNumber, (int)PendingIntentFlags.Immutable);      
            builder.SetContentIntent(resultPendingIntent);      
            // Sending notification      
            var notificationManager = NotificationManagerCompat.From(Application.Context);      
            notificationManager.Notify(randomNumber, builder.Build());      
        }      
    
        private LocalNotification DeserializeNotification(string notificationString){      
    
            var xmlSerializer = new XmlSerializer(typeof(LocalNotification));      
            using (var stringReader = new StringReader(notificationString))      
            {      
                var notification = (LocalNotification)xmlSerializer.Deserialize(stringReader);      
                return notification;      
            }      
        }      
    }      
    

    4.Xamarin.iOS

    Create class LocalNotificationService and implement method LocalNotification and cancel

    public class LocalNotificationService : ILocalNotificationService{      
    
        const string NotificationKey = "LocalNotificationKey";      
    
        public void LocalNotification(string title, string body, int id, DateTime notifyTime){      
    
            var notification = new UILocalNotification{      
    
                AlertTitle = title,      
                AlertBody = body,      
                SoundName = UILocalNotification.DefaultSoundName,      
                FireDate = notifyTime.ToNSDate(),      
                RepeatInterval = NSCalendarUnit.Minute,      
    
                UserInfo = NSDictionary.FromObjectAndKey(NSObject.FromObject(id), NSObject.FromObject(NotificationKey))      
            };      
            UIApplication.SharedApplication.ScheduleLocalNotification(notification);      
        }      
    
        public void Cancel(int id){      
    
            var notifications = UIApplication.SharedApplication.ScheduledLocalNotifications;      
            var notification = notifications.Where(n => n.UserInfo.ContainsKey(NSObject.FromObject(NotificationKey)))      
                .FirstOrDefault(n => n.UserInfo[NotificationKey].Equals(NSObject.FromObject(id)));      
            UIApplication.SharedApplication.CancelAllLocalNotifications();      
            if (notification != null){      
                UIApplication.SharedApplication.CancelLocalNotification(notification);      
                UIApplication.SharedApplication.CancelAllLocalNotifications();      
            }      
        }      
    }      
    
    public static class DateTimeExtensions{      
    
        static DateTime nsUtcRef = new DateTime(2001, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);      
        // last zero is milliseconds      
    
        public static double SecondsSinceNSRefenceDate(this DateTime dt){      
            return (dt.ToUniversalTime() - nsUtcRef).TotalSeconds;      
        }      
    
        public static NSDate ToNSDate(this DateTime dt){      
            return NSDate.FromTimeIntervalSinceReferenceDate(dt.SecondsSinceNSRefenceDate());      
        }      
    }      
    

    For more details, you can enter keywords How To Send Local Notification With A Repeat Interval in your browser to find relative article by Venky Balaraju Balaraju.

    Best Regards,

    Jessie Zhang


    If the response is helpful, please click "Accept Answer" and upvote it.

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    1 person found this answer helpful.

0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.