내 xamarin 양식 응용 프로그램에서 반복 알림 시스템을 구현하려고합니다.이 링크에서 코드를 가져 왔습니다 https://www.c-sharpcorner.com/article/how-to-send-local-notification-with-repeat-interval-in-xamarin-forms/ 및 더 이상 사용되지 않는 코드, 새 코드로 수정 (notif 채널 등)
인 텐트를 만들고 직렬화 된 알림 문자열을 추가하고 15 초 후에 알람 Activity을 시작할 수 있습니다. 중단 점은 15 초 후에 완벽하게 실행되지만 수신 된 인 텐트의 추가 필드에 null 값이 있기 때문에 문자열을 역 직렬화 할 수 없으므로 애플리케이션이 디버깅 모드 및 비 디버깅 모드에서 종료되며 수신 된 알림이 없습니다. .
내 코드는 다음과 같습니다.
이것은 키를 참조하는 데 사용하는 정적 class입니다.
public static class NotificationEssentials
{
public static string channelId = "default";
public static string channelName = "Default";
public static string channelDescription = "The default channel for notifications.";
public static int alarmRequestCode = 8748423;
}
Android 프로젝트의 알림 서비스 class입니다.
public class LocalNotificationService : ILocalNotificationService
{
int _notificationIconId { get; set; }
readonly DateTime _jan1st1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
NotificationManager manager;
public void LocalNotification(string title, string body, int id, DateTime notifyTime)
{
long repeateForMinute = 60000;
long totalMilliSeconds = (long)(notifyTime.ToUniversalTime() - _jan1st1970).TotalMilliseconds;
if (totalMilliSeconds < JavaSystem.CurrentTimeMillis())
totalMilliSeconds = totalMilliSeconds + repeateForMinute;
Intent intent = CreateIntent(id);
LocalNotification localNotification = new LocalNotification
{
Title = title,
Body = body,
Id = id,
NotifyTime = notifyTime
};
if (_notificationIconId != 0)
localNotification.IconId = _notificationIconId;
else
localNotification.IconId = Resource.Drawable.book;
var serializedNotification = SerializeNotification(localNotification);
intent.PutExtra(ScheduledAlarmHandler.LocalNotificationKey, serializedNotification);
var pendingIntent = PendingIntent.GetBroadcast(Application.Context, NotificationEssentials.alarmRequestCode, 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, NotificationEssentials.alarmRequestCode, intent, PendingIntentFlags.Immutable);
var alarmManager = GetAlarmManager();
alarmManager.Cancel(pendingIntent);
NotificationManagerCompat notificationManager = NotificationManagerCompat.From(Application.Context);
notificationManager.CancelAll();
notificationManager.Cancel(id);
}
public static Intent GetLauncherActivity()
{
return Application.Context.PackageManager.GetLaunchIntentForPackage(Application.Context.PackageName);
}
private Intent CreateIntent(int id)
{
return new Intent(Application.Context, typeof(ScheduledAlarmHandler));//.SetAction("LocalNotifierIntent" + id);
}
private AlarmManager GetAlarmManager()
{
return Application.Context.GetSystemService(Context.AlarmService) as AlarmManager;
}
private string SerializeNotification(LocalNotification notification)
{
XmlSerializer xmlSerializer = new XmlSerializer(notification.GetType());
using (var stringWriter = new StringWriter())
{
xmlSerializer.Serialize(stringWriter, notification);
return stringWriter.ToString();
}
}
void CreateNotificationChannel()
{
manager = (NotificationManager)Application.Context.GetSystemService(Context.NotificationService);
if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
{
var channelNameJava = new Java.Lang.String(NotificationEssentials.channelName);
var channel = new NotificationChannel(NotificationEssentials.channelId, channelNameJava, NotificationImportance.Default)
{
Description = NotificationEssentials.channelDescription
};
manager.CreateNotificationChannel(channel);
}
//channelInitialized = true;
}
}
다음은 브로드 캐스트 수신기 class입니다.
[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
NotificationCompat.Builder builder = new NotificationCompat.Builder(Application.Context, NotificationEssentials.channelId)
.SetContentTitle(notification.Title)
.SetContentText(notification.Body)
.SetSmallIcon(notification.IconId)
.SetDefaults((int)NotificationDefaults.Sound | (int)NotificationDefaults.Vibrate);
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(NotificationEssentials.alarmRequestCode, (int)PendingIntentFlags.Immutable);
builder.SetContentIntent(resultPendingIntent);
// Sending notification
var notificationManager = NotificationManagerCompat.From(Application.Context);
notificationManager.Notify(-1, 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;
}
}
}
존경받는 클라이언트 프로젝트 (Android & ios)에서 알람 서비스를 사용하여 로컬 알림을 반복하는 작업 코드를 게시하고 있습니다.
이것은 PCL 프로젝트의 인터페이스입니다.
public interface ILocalNotificationService
{
void LocalNotification(string title, string body, int id, DateTime notifyTime);
void Cancel(int id);
}
이것은 로컬 알림 모델 class입니다.
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; }
}
이것은 안드로이드 프로젝트에서 사용되는 서비스 class입니다.
using System;
using System.IO;
using System.Xml.Serialization;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Support.V4.App;
using YOURAPPLICATION.AppServices;
using YOURAPPLICATION.Droid;
using YOURAPPLICATION.Interfaces;
using Java.Lang;
[assembly: Xamarin.Forms.Dependency(typeof(LocalNotificationService))]
namespace YOURAPPLICATION.Droid
{
public static class NotificationEssentials
{
public static string channelId = "default";
public static string channelName = "Default";
public static string channelDescription = "The default channel for notifications.";
public static int alarmRequestCode = 8748423;
}
public class LocalNotificationService : ILocalNotificationService
{
int _notificationIconId { get; set; }
readonly DateTime _jan1st1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
public void LocalNotification(string title, string body, int id, DateTime notifyTime)
{
long repeatEachDay = 1000 * 60 * 60 * 24;
//long repeateEachMinute = 60000;
long totalMilliSeconds = (long)(notifyTime.ToUniversalTime() - _jan1st1970).TotalMilliseconds;
if (totalMilliSeconds < JavaSystem.CurrentTimeMillis())
totalMilliSeconds = totalMilliSeconds + repeatEachDay;
Intent intent = CreateIntent(id);
LocalNotification localNotification = new LocalNotification
{
Title = title,
Body = body,
Id = id,
NotifyTime = notifyTime
};
if (_notificationIconId != 0)
localNotification.IconId = _notificationIconId;
else
localNotification.IconId = Resource.Drawable.book;
var serializedNotification = SerializeNotification(localNotification);
intent.PutExtra(ScheduledAlarmHandler.LocalNotificationKey, serializedNotification);
Random generator = new Random();
string 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, repeatEachDay, pendingIntent);
}
public void Cancel(int id)
{
var intent = CreateIntent(id);
var pendingIntent = PendingIntent.GetBroadcast(Application.Context, NotificationEssentials.alarmRequestCode, intent, PendingIntentFlags.Immutable);
var alarmManager = GetAlarmManager();
alarmManager.Cancel(pendingIntent);
NotificationManagerCompat notificationManager = NotificationManagerCompat.From(Application.Context);
notificationManager.CancelAll();
notificationManager.Cancel(id);
}
public static Intent GetLauncherActivity()
{
return Application.Context.PackageManager.GetLaunchIntentForPackage(Application.Context.PackageName);
}
private Intent CreateIntent(int id)
{
return new Intent(Application.Context, typeof(ScheduledAlarmHandler)).SetAction("LocalNotifierIntent" + id);
}
private AlarmManager GetAlarmManager()
{
return Application.Context.GetSystemService(Context.AlarmService) as AlarmManager;
}
private string SerializeNotification(LocalNotification notification)
{
XmlSerializer 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";
bool channelInitialized = false;
NotificationManager manager;
public override void OnReceive(Context context, Intent intent)
{
var extra = intent.GetStringExtra(LocalNotificationKey);
var notification = DeserializeNotification(extra);
if (!channelInitialized)
{
CreateNotificationChannel();
}
NotificationCompat.Builder builder = new NotificationCompat.Builder(Application.Context, NotificationEssentials.channelId)
.SetContentTitle(notification.Title)
.SetContentText(notification.Body)
.SetSmallIcon(notification.IconId)
.SetAutoCancel(true)
.SetStyle(new NotificationCompat.BigTextStyle()
.BigText("Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."))
.SetDefaults((int)NotificationDefaults.Sound | (int)NotificationDefaults.Vibrate);
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);
manager.Notify(randomNumber, builder.Build());
}
void CreateNotificationChannel()
{
manager = (NotificationManager)Application.Context.GetSystemService(Context.NotificationService);
if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
{
var channelNameJava = new Java.Lang.String(NotificationEssentials.channelName);
var channel = new NotificationChannel(NotificationEssentials.channelId, channelNameJava, NotificationImportance.Default)
{
Description = NotificationEssentials.channelDescription
};
manager.CreateNotificationChannel(channel);
}
//channelInitialized = true;
}
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;
}
}
}
}
마지막으로 IOS 서비스 class
using System;
using System.Linq;
using Foundation;
using UIKit;
using Xamarin.Forms;
using IslamicApp.iOS;
using IslamicApp.Interfaces;
[assembly: Dependency(typeof(LocalNotificationService))]
namespace IslamicApp.iOS
{
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());
}
}
}
그게 다입니다
참고 :이 코드가 IOS에서 예상대로 작동하는지 확인하지 않았습니다.
업데이트 : 다음은 PCL의 사용법입니다.
var SelectedDate = DateTime.Now;
var SelectedTime = DateTime.Now.AddMinutes(1);
var date = (SelectedDate.Date.Month.ToString("00") + "-" + SelectedDate.Date.Day.ToString("00") + "-" + SelectedDate.Date.Year.ToString());
var time = Convert.ToDateTime(SelectedTime.ToString()).ToString("HH:mm");
var dateTime = date + " " + time;
var selectedDateTime = DateTime.ParseExact(dateTime, "MM-dd-yyyy HH:mm", CultureInfo.InvariantCulture);
DependencyService.Get<ILocalNotificationService>().Cancel(0);
DependencyService.Get<ILocalNotificationService>().LocalNotification("Sample Notification",
"Hi, This is a sample notification from Xamarin forms", 0, selectedDateTime);