How To Send Local Notification With A Repeat Interval (Day/Minute/Hour etc.)

Introduction

In this article, we will learn how to send Local Notifications for a particular date and time at a repeated interval (Day/Minute/Hour etc.,) using the DependencyService concept in Xamarin.Forms.

Xamarin

Requirements
  • This article's source code is prepared by using Visual Studio. It is better to install the latest Visual Studio updates from here.
  • This article is prepared on a MAC machine.
  • This sample project is in Xamarin.Forms of PCL project.
  • This sample app is targeted for Android, iOS. And tested for Android & iOS.
Description

Let's start.

Step 1

First, follow the below steps to create the new Xamarin.Forms project.

  1. Open Visual Studio for Mac.
  2. Click on the File menu and select New Solution.
  3. In the left pane of the dialog, let's select the type of templates to display. Multiplatform > App > Xamarin.Forms > Blank Forms App and click "Next".
  4. Next, enter your app name (Ex: LocalNotificationDemo). At the bottom, select target platforms to Android & iOS and shared code to Portable Class Library and click the "Next" button.
  5. Then, choose project location with the help of Browse button and click "Create".
Now, the project structure will be created like below.
  • LocalNotificationDemo
    It is for Shared Code
  • LocalNotificationDemo.Droid
    It is for Android.

  • LocalNotificationDemo.iOS
    It is for iOS.

Step 2

Local notifications will helpful to send application-related data at some time through notifications.

Xamarin

In this article we will do the below steps for getting local notification with repeat at an interval.
  • Taking Switch for notifications on or off.
  • Taking TimePicker and DatePicker for scheduling local notification.
  • Converting TimePicker selected time, DatePicker selectedDate to DateTime type and passing datetime to DependencyService.
  • Taking Editor and passing editor text as a notification message.
  • Save button. In this, we are checking if notification is on or off. If notification switch is on then we call Dependency Service to schedule notification.
  • In Platform specific, we are scheduling notification and giving repeat interval time like Day/Minute/Hour etc,.
Portable class library(PCL)

Views

Create your own XAML page named LocalNotificationPage.xaml inside the Views folder. And here, we are taking inputs from users like notification On/Off, date, time and message text.

LocalNotificationPage.xaml

Save this link to your bookmarks to access the best free online web developer tools and use them every day: html-css-js.com.

  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"  
  3.     xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"  
  4.     x:Class="LocalNotificationDemo.Views.LocalNotificationPage"  
  5.     Title="Local Notification"  
  6.     BackgroundColor="#533F95">  
  7.     <ContentPage.Content>  
  8.         <Grid VerticalOptions="FillAndExpand" Padding="25,40,25,30" RowSpacing="20">  
  9.             <Grid.RowDefinitions>  
  10.                 <RowDefinition Height="Auto"/>  
  11.                 <RowDefinition Height="Auto"/>  
  12.                 <RowDefinition Height="Auto"/>  
  13.                 <RowDefinition Height="Auto"/>  
  14.                 <RowDefinition Height="Auto"/>  
  15.             </Grid.RowDefinitions>  
  16.             <Grid Grid.Row="0">  
  17.                 <StackLayout HorizontalOptions="FillAndExpand" Orientation="Horizontal">  
  18.                     <Label Text="Notifications ON/OFF" TextColor="White" FontSize="16" HorizontalOptions="StartAndExpand" VerticalOptions="Center"/>  
  19.                     <Switch IsToggled=" {Binding NotificationONOFF}" HorizontalOptions="EndAndExpand" VerticalOptions="Center"/>  
  20.                 </StackLayout>  
  21.             </Grid>  
  22.             <Grid Grid.Row="1">  
  23.                 <StackLayout HorizontalOptions="FillAndExpand" Orientation="Horizontal">  
  24.                 <Label Text="SET TIME" HorizontalOptions="StartAndExpand" FontSize="15" TextColor="White" VerticalOptions="Center"/>  
  25.                 <TimePicker HorizontalOptions="EndAndExpand" Time=" {Binding SelectedTime}" TextColor="White" BackgroundColor="Transparent" Format="t"/>  
  26.                 </StackLayout>  
  27.             </Grid>  
  28.             <Grid Grid.Row="2">  
  29.                  <StackLayout HorizontalOptions="FillAndExpand" Orientation="Horizontal">  
  30.                 <Label Text="SET DATE" TextColor="White" FontSize="15" VerticalOptions="Center" HorizontalOptions="StartAndExpand"/>  
  31.                  <DatePicker HorizontalOptions="EndAndExpand" Date=" {Binding SelectedDate}" TextColor="White"  BackgroundColor="Transparent" Format="MM-dd-yyyy"/>  
  32.                 </StackLayout>  
  33.             </Grid>  
  34.             <Grid Grid.Row="3">  
  35.                 <StackLayout HorizontalOptions="FillAndExpand" Spacing="10">  
  36.                  <Label Text="Enter Message" FontSize="15" HorizontalOptions="StartAndExpand" TextColor="White" VerticalOptions="Center"/>  
  37.                  <Editor HeightRequest="120" Text=" {Binding MessageText}" TextColor="Purple" BackgroundColor="White" HorizontalOptions="FillAndExpand"/>  
  38.                 </StackLayout>  
  39.             </Grid>  
  40.             <Grid Grid.Row="4">  
  41.                 <Button Text="Save" Command="{Binding SaveCommand}" FontSize="15" TextColor="White" BackgroundColor="Purple"  HorizontalOptions="FillAndExpand" BorderRadius="15"/>  
  42.             </Grid>  
  43.         </Grid>  
  44.     </ContentPage.Content>  
  45. </ContentPage>  

LocalNotificationPage.xaml.cs

Make BindingContext in code behind with LocalNotificationPageViewModel.

  1. using LocalNotifcationDemo.ViewModels;  
  2. using Xamarin.Forms;  
  3. namespace LocalNotifcationDemo.Views {  
  4.     public partial class LocalNotificationPage: ContentPage {  
  5.         public LocalNotificationPage() {  
  6.             InitializeComponent();  
  7.             BindingContext = new LocalNotificationPageViewModel();  
  8.         }  
  9.     }  

ViewModels

LocalNotificationPageViewModel.cs

In this ViewModel, we are calling DependencyService and passing the selected date, time and message text to the service.

Properties

  • NotificationONOFF
  • SelectedDate
  • SelectedTime
  • MessageText

Commands

  • SaveCommand  
  1. using System;    
  2. using System.Collections.Generic;    
  3. using System.ComponentModel;    
  4. using System.Globalization;    
  5. using System.Runtime.CompilerServices;    
  6. using LocalNotificationDemo.DependencyServices;    
  7. using Xamarin.Forms;    
  8. namespace LocalNotificationDemo.ViewModels {    
  9.     public class LocalNotificationPageViewModel: INotifyPropertyChanged {    
  10.         Command _saveCommand;    
  11.         public Command SaveCommand {    
  12.             get {    
  13.                 return _saveCommand;    
  14.             }    
  15.             set {    
  16.                 SetProperty(ref _saveCommand, value);    
  17.             }    
  18.         }    
  19.         bool _notificationONOFF;    
  20.         public bool NotificationONOFF {    
  21.             get {    
  22.                 return _notificationONOFF;    
  23.             }    
  24.             set {    
  25.                 SetProperty(ref _notificationONOFF, value);    
  26.                 Switch_Toggled();    
  27.             }    
  28.         }    
  29.         void Switch_Toggled() {    
  30.             if (NotificationONOFF == false) {    
  31.                 MessageText = string.Empty;    
  32.                 SelectedTime = DateTime.Now.TimeOfDay;    
  33.                 SelectedDate = DateTime.Today;    
  34.                 DependencyService.Get<ILocalNotificationService>().Cancel(0);    
  35.             }    
  36.         }    
  37.         DateTime _selectedDate = DateTime.Today;    
  38.         public DateTime SelectedDate {    
  39.             get {    
  40.                 return _selectedDate;    
  41.             }    
  42.             set {    
  43.                 SetProperty(ref _selectedDate, value);    
  44.             }    
  45.         }    
  46.         TimeSpan _selectedTime = DateTime.Now.TimeOfDay;    
  47.         public TimeSpan SelectedTime {    
  48.             get {    
  49.                 return _selectedTime;    
  50.             }    
  51.             set {    
  52.                 SetProperty(ref _selectedTime, value);    
  53.             }    
  54.         }    
  55.         string _messageText;    
  56.         public string MessageText {    
  57.             get {    
  58.                 return _messageText;    
  59.             }    
  60.             set {    
  61.                 SetProperty(ref _messageText, value);    
  62.             }    
  63.         }    
  64.         public LocalNotificationPageViewModel() {    
  65.             SaveCommand = new Command(() => SaveLocalNotification());    
  66.         }    
  67.         void SaveLocalNotification() {    
  68.             if (NotificationONOFF == true) {    
  69.                 var date = (SelectedDate.Date.Month.ToString("00") + "-" + SelectedDate.Date.Day.ToString("00") + "-" + SelectedDate.Date.Year.ToString());    
  70.                 var time = Convert.ToDateTime(SelectedTime.ToString()).ToString("HH:mm");    
  71.                 var dateTime = date + " " + time;    
  72.                 var selectedDateTime = DateTime.ParseExact(dateTime, "MM-dd-yyyy HH:mm", CultureInfo.InvariantCulture);    
  73.                 if (!string.IsNullOrEmpty(MessageText)) {    
  74.                     DependencyService.Get<ILocalNotificationService>().Cancel(0);    
  75.     DependencyService.Get<ILocalNotificationService().LocalNotification("Local Notification"MessageText, 0, selectedDateTime);    
  76.                     App.Current.MainPage.DisplayAlert("LocalNotificationDemo""Notification details saved successfully ""Ok");    
  77.                 } else {    
  78.                     App.Current.MainPage.DisplayAlert("LocalNotificationDemo""Please enter meassage""OK");    
  79.                 }    
  80.             } else {    
  81.                 App.Current.MainPage.DisplayAlert("LocalNotificationDemo""Please switch on notification""OK");    
  82.             }    
  83.         }    
  84.         protected bool SetProperty<T> (ref T backingStore, T value, [CallerMemberName] string propertyName = "", Action onChanged = null) {    
  85.             if (EqualityComparer<T>.Default.Equals(backingStore, value))   
  86.                  return false;    
  87.             backingStore = value;    
  88.             onChanged?.Invoke();    
  89.             OnPropertyChanged(propertyName);    
  90.             return true;    
  91.         }    
  92.         public event PropertyChangedEventHandler PropertyChanged;    
  93.         protected void OnPropertyChanged([CallerMemberName] string propertyName = "") {    
  94.             var changed = PropertyChanged;    
  95.             if (changed == null)   
  96.                  return;    
  97.             changed.Invoke(thisnew PropertyChangedEventArgs(propertyName));    
  98.         }    
  99.     }    
  100. }  
Step 3
 
Portable class library (PCL)

Create an interface ILocalNotificationService inside the DependencyServices folder that has the methods declaration of LocalNotification and Cancel.

ILocalNotificationService.cs

  1. using System;    
  2.     
  3. namespace LocalNotificationDemo.DependencyServices    
  4. {    
  5.     public interface ILocalNotificationService    
  6.     {    
  7.         void LocalNotification(string title, string body, int id, DateTime notifyTime);    
  8.         void Cancel(int id);    
  9.     }    
  10. }    
Models

In models, we need to create the below class with Title, Body, ID, IconId and NotifyTime. It will be useful to pass a local notification data to BroadcastReceiver receiver for repeating in Android.

LocalNotification.cs

  1. using System;    
  2. namespace LocalNotificationDemo.Models{    
  3.         
  4.     public class LocalNotification{    
  5.     
  6.         public string Title { getset; }    
  7.     
  8.         public string Body { getset; }    
  9.     
  10.         public int Id { getset; }    
  11.     
  12.         public int IconId { getset; }    
  13.     
  14.         public DateTime NotifyTime { getset; }    
  15.     }    
  16. }   

Step 4

Xamarin.Android

Create a class LocalNotificationService and we need to implement LocalNotification and Cancel methods like below. In this, we have created BroadcastReceiver for repeating notification.

LocalNotificationService.cs

  1. using System;    
  2. using System.IO;    
  3. using System.Xml.Serialization;    
  4. using Android.App;    
  5. using Android.Content;    
  6. using Android.Media;    
  7. using Android.Support.V4.App;    
  8. using Java.Lang;    
  9. using LocalNotificationDemo.DependencyServices.Droid;    
  10. using LocalNotificationDemo.Droid;    
  11. using LocalNotificationDemo.Models;    
  12.     
  13. [assembly: Xamarin.Forms.Dependency(typeof(LocalNotificationService))]    
  14.     
  15. namespace LocalNotificationDemo.DependencyServices.Droid{    
  16.         
  17.     public class LocalNotificationService : ILocalNotificationService    
  18.     {    
  19.         int _notificationIconId { getset; }    
  20.         readonly DateTime _jan1st1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);    
  21.         internal string _randomNumber;    
  22.     
  23.         public void LocalNotification(string title, string body, int id, DateTime notifyTime){    
  24.                 
  25.             //long repeateDay = 1000 * 60 * 60 * 24;    
  26.             long repeateForMinute = 60000; // In milliseconds   
  27.             long totalMilliSeconds = (long)(notifyTime.ToUniversalTime() - _jan1st1970).TotalMilliseconds;    
  28.             if (totalMilliSeconds < JavaSystem.CurrentTimeMillis()){    
  29.                 totalMilliSeconds = totalMilliSeconds + repeateForMinute;    
  30.             }    
  31.     
  32.             var intent = CreateIntent(id);    
  33.             var localNotification = new LocalNotification();    
  34.             localNotification.Title = title;    
  35.             localNotification.Body = body;    
  36.             localNotification.Id = id;    
  37.             localNotification.NotifyTime = notifyTime;    
  38.     
  39.             if (_notificationIconId != 0){    
  40.                 localNotification.IconId = _notificationIconId;    
  41.             }    
  42.             else{    
  43.                 localNotification.IconId = Resource.Drawable.notificationgrey;    
  44.             }    
  45.     
  46.             var serializedNotification = SerializeNotification(localNotification);    
  47.             intent.PutExtra(ScheduledAlarmHandler.LocalNotificationKey, serializedNotification);    
  48.     
  49.             Random generator = new Random();      
  50.             _randomNumber = generator.Next(100000, 999999).ToString("D6");     
  51.     
  52.             var pendingIntent = PendingIntent.GetBroadcast(Application.Context, Convert.ToInt32(_randomNumber), intent, PendingIntentFlags.Immutable);    
  53.             var alarmManager = GetAlarmManager();    
  54.             alarmManager.SetRepeating(AlarmType.RtcWakeup, totalMilliSeconds, repeateForMinute, pendingIntent);    
  55.         }    
  56.          
  57.         public void Cancel(int id){    
  58.                 
  59.             var intent = CreateIntent(id);    
  60.             var pendingIntent = PendingIntent.GetBroadcast(Application.Context, Convert.ToInt32(_randomNumber), intent, PendingIntentFlags.Immutable);    
  61.             var alarmManager = GetAlarmManager();    
  62.             alarmManager.Cancel(pendingIntent);    
  63.             var notificationManager = NotificationManagerCompat.From(Application.Context);    
  64.             notificationManager.CancelAll();    
  65.             notificationManager.Cancel(id);    
  66.         }    
  67.     
  68.         public static Intent GetLauncherActivity(){    
  69.                 
  70.             var packageName = Application.Context.PackageName;    
  71.             return Application.Context.PackageManager.GetLaunchIntentForPackage(packageName);    
  72.         }    
  73.     
  74.     
  75.         private Intent CreateIntent(int id){    
  76.                 
  77.             return new Intent(Application.Context, typeof(ScheduledAlarmHandler))    
  78.                 .SetAction("LocalNotifierIntent" + id);    
  79.         }    
  80.     
  81.         private AlarmManager GetAlarmManager(){    
  82.                 
  83.             var alarmManager = Application.Context.GetSystemService(Context.AlarmService) as AlarmManager;    
  84.             return alarmManager;    
  85.         }    
  86.     
  87.         private string SerializeNotification(LocalNotification notification){    
  88.                 
  89.             var xmlSerializer = new XmlSerializer(notification.GetType());    
  90.     
  91.             using (var stringWriter = new StringWriter()){    
  92.                 xmlSerializer.Serialize(stringWriter, notification);    
  93.                 return stringWriter.ToString();    
  94.             }    
  95.         }    
  96.     }    
  97.     
  98.     [BroadcastReceiver(Enabled = true, Label = "Local Notifications Broadcast Receiver")]    
  99.     public class ScheduledAlarmHandler : BroadcastReceiver{    
  100.     
  101.         public const string LocalNotificationKey = "LocalNotification";    
  102.     
  103.         public override void OnReceive(Context context, Intent intent){    
  104.             var extra = intent.GetStringExtra(LocalNotificationKey);    
  105.             var notification = DeserializeNotification(extra);    
  106.             //Generating notification    
  107.             var builder = new NotificationCompat.Builder(Application.Context)    
  108.                 .SetContentTitle(notification.Title)    
  109.                 .SetContentText(notification.Body)    
  110.                 .SetSmallIcon(notification.IconId)    
  111.                 .SetSound(RingtoneManager.GetDefaultUri(RingtoneType.Ringtone))    
  112.                 .SetAutoCancel(true);    
  113.     
  114.             var resultIntent = LocalNotificationService.GetLauncherActivity();    
  115.             resultIntent.SetFlags(ActivityFlags.NewTask | ActivityFlags.ClearTask);    
  116.             var stackBuilder = Android.Support.V4.App.TaskStackBuilder.Create(Application.Context);    
  117.             stackBuilder.AddNextIntent(resultIntent);    
  118.     
  119.             Random random = new Random();    
  120.             int randomNumber = random.Next(9999 - 1000) + 1000;     
  121.     
  122.             var resultPendingIntent =    
  123.                 stackBuilder.GetPendingIntent(randomNumber, (int)PendingIntentFlags.Immutable);    
  124.             builder.SetContentIntent(resultPendingIntent);    
  125.             // Sending notification    
  126.             var notificationManager = NotificationManagerCompat.From(Application.Context);    
  127.             notificationManager.Notify(randomNumber, builder.Build());    
  128.         }    
  129.     
  130.         private LocalNotification DeserializeNotification(string notificationString){    
  131.                 
  132.             var xmlSerializer = new XmlSerializer(typeof(LocalNotification));    
  133.             using (var stringReader = new StringReader(notificationString))    
  134.             {    
  135.                 var notification = (LocalNotification)xmlSerializer.Deserialize(stringReader);    
  136.                 return notification;    
  137.             }    
  138.         }    
  139.     }    
  140. }   

Note

In Android, we are using AlarmManger for repeating location notifications.

Step 5

Xamarin.iOS

Now, create a class LocalNotificationService and implement LocalNotification and cancel the method like below.

LocalNotificationService.cs

  1. using System;    
  2. using UIKit;    
  3. using Foundation;    
  4. using System.Linq;    
  5. using Xamarin.Forms;    
  6. using LocalNotificationDemo.iOS;    
  7. using LocalNotificationDemo.DependencyServices;    
  8.     
  9. [assembly: Dependency(typeof(LocalNotificationService))]    
  10. namespace LocalNotificationDemo.iOS{    
  11.         
  12.     public class LocalNotificationService : ILocalNotificationService{    
  13.             
  14.         const string NotificationKey = "LocalNotificationKey";    
  15.     
  16.         public void LocalNotification(string title, string body, int id, DateTime notifyTime){    
  17.                 
  18.             var notification = new UILocalNotification{    
  19.                     
  20.                 AlertTitle = title,    
  21.                 AlertBody = body,    
  22.                 SoundName = UILocalNotification.DefaultSoundName,    
  23.                 FireDate = notifyTime.ToNSDate(),    
  24.                 RepeatInterval = NSCalendarUnit.Minute,    
  25.     
  26.                 UserInfo = NSDictionary.FromObjectAndKey(NSObject.FromObject(id), NSObject.FromObject(NotificationKey))    
  27.             };    
  28.             UIApplication.SharedApplication.ScheduleLocalNotification(notification);    
  29.         }    
  30.     
  31.         public void Cancel(int id){    
  32.                 
  33.             var notifications = UIApplication.SharedApplication.ScheduledLocalNotifications;    
  34.             var notification = notifications.Where(n => n.UserInfo.ContainsKey(NSObject.FromObject(NotificationKey)))    
  35.                 .FirstOrDefault(n => n.UserInfo[NotificationKey].Equals(NSObject.FromObject(id)));    
  36.             UIApplication.SharedApplication.CancelAllLocalNotifications();    
  37.             if (notification != null){    
  38.                 UIApplication.SharedApplication.CancelLocalNotification(notification);    
  39.                 UIApplication.SharedApplication.CancelAllLocalNotifications();    
  40.             }    
  41.         }    
  42.     }    
  43.     
  44.     public static class DateTimeExtensions{    
  45.             
  46.         static DateTime nsUtcRef = new DateTime(2001, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);    
  47.         // last zero is milliseconds    
  48.     
  49.         public static double SecondsSinceNSRefenceDate(this DateTime dt){    
  50.             return (dt.ToUniversalTime() - nsUtcRef).TotalSeconds;    
  51.         }    
  52.     
  53.         public static NSDate ToNSDate(this DateTime dt){    
  54.             return NSDate.FromTimeIntervalSinceReferenceDate(dt.SecondsSinceNSRefenceDate());    
  55.         }    
  56.     }    
  57. }   

Note

In iOS, UILocationNotification is having RepeatIntervel property. It will be useful to repeat the notification by Day/Minute.

Xamarin

AppDelegate.cs

In AppDelegate.cs, first, add the following code to the FinishedLaunching method. We have checked to see if the device is running iOS 8. If so, we are required to ask for the user's permission to receive notifications.

  1. // We have checked to see if the device is running iOS 8, if so we are required to ask for the user's permission to receive notifications    
  2.             if (UIDevice.CurrentDevice.CheckSystemVersion(8, 0)){    
  3.                 var notificationSettings = UIUserNotificationSettings.GetSettingsForTypes(    
  4.                     UIUserNotificationType.Alert | UIUserNotificationType.Badge | UIUserNotificationType.Sound, null    
  5.                 );    
  6.     
  7.                 app.RegisterUserNotificationSettings(notificationSettings);    
  8.             }     

Still, in AppDelegate.cs, add the following method which will be called when a notification is received.

  1. public override void ReceivedLocalNotification(UIApplication application, UILocalNotification notification){    
  2.                 
  3.             UIAlertController okayAlertController = UIAlertController.Create(notification.AlertAction, notification.AlertBody, UIAlertControllerStyle.Alert);    
  4.             okayAlertController.AddAction(UIAlertAction.Create("OK", UIAlertActionStyle.Default, null));    
  5.             UIApplication.SharedApplication.ApplicationIconBadgeNumber = 0;    
  6.         }     

We need to handle the case where the notification was launched because of a local notification. Edit the method FinishedLaunching in the AppDelegate to include the following snippet of code.

  1. // check for a notification    
  2.             if (options != null){    
  3.                 if (options.ContainsKey(UIApplication.LaunchOptionsLocalNotificationKey)){    
  4.                     UILocalNotification localNotification = options[UIApplication.LaunchOptionsLocalNotificationKey] as UILocalNotification;    
  5.                     if (localNotification != null){    
  6.                         new UIAlertView(localNotification.AlertAction, localNotification.AlertBody, null"OK"null).Show();    
  7.                         // reset our badge    
  8.                         UIApplication.SharedApplication.ApplicationIconBadgeNumber = 0;    
  9.                     }    
  10.            }    
  11.   
 On iOS 8 we will be prompted to allow notifications like below.
 
Xamarin
Output

Please download the source code from here.

Xamarin  Xamarin

X

Build smarter apps with Machine Learning, Bots, Cognitive Services - Start free.

Start Learning Now