C# - Xamarin Forms断电后没有收到本地通知
问题描述:
我已经为我的Xamarin应用程序实施了通知服务,除非我关掉手机。有没有办法启动服务,以确保即使在设备关闭后也能传递通知?C# - Xamarin Forms断电后没有收到本地通知
接口:
public interface INotification
{
void Remind(long date, string title, string message);
}
在Android文件执行:
using Xamarin.Forms;
using Plannr.Droid;
using Android.Support.V4.App;
using Android.Content;
using Android.App;
using Android.OS;
[assembly: Dependency(typeof(Notification_Android))]
namespace Plannr.Droid
{
public class Notification_Android : INotification
{
void INotification.Remind(long date, string title, string message)
{
Intent alarmIntent = new Intent(Forms.Context, typeof(AlarmReceiver));
alarmIntent.PutExtra("message", message);
alarmIntent.PutExtra("title", title);
PendingIntent pendingIntent = PendingIntent.GetBroadcast(Forms.Context, 0, alarmIntent, 0);
AlarmManager alarmManager = (AlarmManager)Forms.Context.GetSystemService(Context.AlarmService);
//TODO: For demo set after 5 seconds.
alarmManager.Set(AlarmType.ElapsedRealtime, SystemClock.ElapsedRealtime() + date, pendingIntent);
}
[BroadcastReceiver]
public class AlarmReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
var message = intent.GetStringExtra("message");
var title = intent.GetStringExtra("title");
var notIntent = context.PackageManager.GetLaunchIntentForPackage(context.PackageName);
intent.AddFlags(ActivityFlags.ClearTop);
notIntent.AddFlags(ActivityFlags.ClearTop);
var contentIntent = PendingIntent.GetActivity(context, 0, notIntent, PendingIntentFlags.UpdateCurrent);
var manager = NotificationManagerCompat.From(context);
var style = new NotificationCompat.BigTextStyle();
style.BigText(message);
//Generate a notification with just short text and small icon
var builder = new NotificationCompat.Builder(context)
.SetSmallIcon(Resource.Drawable.icon)
.SetContentIntent(contentIntent)
.SetContentTitle(title)
.SetContentText(message)
.SetStyle(style)
.SetWhen(Java.Lang.JavaSystem.CurrentTimeMillis())
.SetAutoCancel(true);
builder.SetVibrate((new long[] { 300, 200, 100, 200}));
var notification = builder.Build();
Android.App.Application.Context.StartService(intent);
manager.Notify(1, notification);
}
}
}
}
答
你必须有一个服务和广播接收器这样的事情(这是一个古老的代码):
Android依赖服务:
using System;
using XXX.Droid.LocalNotifications.Dependency;
using XXX.LocalNotifications.Interfaces;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Android.Content;
using Android.App;
using Xamarin.Forms;
using XXX.LocalNotifications;
[assembly: Dependency (typeof (LocalNotificationManager_Android))]
namespace XXX.Droid.LocalNotifications.Dependency
{
public class LocalNotificationManager_Android: ILocalNotificationManager
{
#region ILocalNotificationManager implementation
public void RegisterLocalNotification (Notification notification)
{
RegisterNotification (notification);
}
public void RegisterLocalNotification (List<Notification> notifications)
{
foreach (var notification in notifications) {
RegisterNotification (notification);
}
}
public void UnRegisterLocalNotification (Notification notification)
{
var localNotification = File.ReadAllLines (LogFilePath).FirstOrDefault (noti => noti == notification.Guid);
if (!string.IsNullOrWhiteSpace (localNotification)) {
UnRegisterNotification (notification);
}
}
public void UnRegisterLocalNotification (List<Notification> notifications)
{
foreach (var notification in notifications) {
var localNotification = File.ReadAllLines (LogFilePath).FirstOrDefault (noti => noti == notification.Guid);
if (!string.IsNullOrWhiteSpace (localNotification)) {
UnRegisterNotification (notification);
}
}
}
public void UnRegisterAllNotifications()
{
try{
var notificationInfo = File.ReadAllLines(LogFilePath);
foreach(var line in notificationInfo)
{
try{
var notification = new Notification(line);
UnRegisterNotification(notification);
}catch(Exception ex){
Console.WriteLine(ex.Message);
}
}
File.Delete(LogFilePath);
}catch(Exception ex){
Console.WriteLine(ex.Message);
}
}
public void RegisterService()
{
if (!File.Exists (LogFilePath)) {
var file= File.Create (LogFilePath);
file.Close();
}
}
public bool IsServiceRegistered {
get {
return true;
}
}
#endregion
private string LogFilePath
{
get{
var documents = Environment.GetFolderPath (Environment.SpecialFolder.MyDocuments);
var logFile = Path.Combine (documents, "notificationsinfo.txt");
if (!File.Exists (logFile)) {
var file= File.Create (logFile);
file.Close();
}
return logFile;
}
}
private void UnRegisterNotification(Notification notification)
{
Intent intent1 = new Intent(Forms.Context, typeof(CalendarReceiver));
intent1.SetData (Android.Net.Uri.Parse ("custom://" + notification.Guid));
intent1.SetAction (notification.Guid);
intent1.PutExtra ("Title", notification.Title);
intent1.PutExtra ("Message", notification.Message);
PendingIntent pendingIntent = PendingIntent.GetBroadcast(
Forms.Context, 0, intent1,
PendingIntentFlags.UpdateCurrent);
try{
AndroidAlarmManager.Cancel (pendingIntent);
var notificationInfo = new List<string>(File.ReadAllLines(LogFilePath));
notificationInfo.Remove(notification.Guid);
File.WriteAllLines(LogFilePath, notificationInfo);
}catch(Exception ex) {
Console.WriteLine(ex.Message);
}
}
private void RegisterNotification(Notification notification)
{
if (string.IsNullOrWhiteSpace (notification.Title)) {
throw new NullReferenceException ("Title must be setted");
}
if (string.IsNullOrWhiteSpace(notification.Message)) {
throw new NullReferenceException ("Message must be setted");
}
if (!notification.Date.HasValue) {
throw new NullReferenceException ("DateTime must be setted");
}
if (notification.Date < DateTime.Now && notification.Interval == RepeatInterval.None) {
throw new ArgumentException ("DateTime must be greater than DateTime.Now");
}
Intent intent1 = new Intent(Forms.Context, typeof(CalendarReceiver));
intent1.SetData (Android.Net.Uri.Parse ("custom://" + notification.Guid));
intent1.SetAction (notification.Guid);
intent1.PutExtra ("Title", notification.Title);
intent1.PutExtra ("Message", notification.Message);
var daysInCurrentMonth = DateTime.DaysInMonth(DateTime.Now.Year, DateTime.Now.Month);
PendingIntent pendingIntent = PendingIntent.GetBroadcast(
Forms.Context, 0, intent1,
PendingIntentFlags.UpdateCurrent);
switch (notification.Interval)
{
case RepeatInterval.Daily:
AndroidAlarmManager.SetRepeating(AlarmType.RtcWakeup, GetMilisecondsUntilNextCheck(notification.Date.Value),
AlarmManager.IntervalDay, pendingIntent);
break;
case RepeatInterval.Weekly:
AndroidAlarmManager.SetRepeating(AlarmType.RtcWakeup, GetMilisecondsUntilNextCheck(notification.Date.Value),
AlarmManager.IntervalDay * 7, pendingIntent);
break;
case RepeatInterval.Monthly:
AndroidAlarmManager.SetRepeating(AlarmType.RtcWakeup, GetMilisecondsUntilNextCheck(notification.Date.Value),
AlarmManager.IntervalDay * daysInCurrentMonth, pendingIntent);
break;
case RepeatInterval.None:
AndroidAlarmManager.Set(AlarmType.RtcWakeup, GetMilisecondsUntilNextCheck(notification.Date.Value), pendingIntent);
break;
}
try{
var notificationInfo = new List<string>(File.ReadAllLines(LogFilePath));
notificationInfo.Add(notification.Guid);
File.WriteAllLines(LogFilePath, notificationInfo);
}catch(Exception ex){
Console.WriteLine(ex.Message);
}
}
public static long GetMilisecondsUntilNextCheck(DateTime next)
{
DateTime now = DateTime.Now;
DateTime todayAtTime = now.Date.AddHours(next.Hour).AddMinutes(next.Minute);
DateTime nextInstance = now <= todayAtTime ? todayAtTime : todayAtTime.AddDays(1);
TimeSpan span = nextInstance - now;
using (var cal = Java.Util.Calendar.GetInstance(Java.Util.TimeZone.Default))
{
cal.Set (Java.Util.CalendarField.Millisecond, 0);
cal.Add(Java.Util.CalendarField.Millisecond, (int)span.TotalMilliseconds);
return cal.TimeInMillis;
}
}
public void UnRegisterLocalNotification(string notificationGuid)
{
Intent intent1 = new Intent(Forms.Context, typeof(CalendarReceiver));
intent1.SetData(Android.Net.Uri.Parse("custom://" + notificationGuid));
intent1.SetAction(notificationGuid);
PendingIntent pendingIntent = PendingIntent.GetBroadcast(
Forms.Context, 0, intent1,
PendingIntentFlags.UpdateCurrent);
try
{
AndroidAlarmManager.Cancel(pendingIntent);
var notificationInfo = new List<string>(File.ReadAllLines(LogFilePath));
notificationInfo.Remove(notificationGuid);
File.WriteAllLines(LogFilePath, notificationInfo);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
AlarmManager AndroidAlarmManager { get; set; }
public LocalNotificationManager_Android()
{
AndroidAlarmManager = (AlarmManager) Forms.Context.GetSystemService(Context.AlarmService);
}
}
}
CalendarAlarmService:
using System;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Support.V7.App;
namespace XXX.Droid.LocalNotifications
{
[Service(Enabled = true)]
public class CalendarAlarmService : Service
{
ServiceBinder binder;
NotificationManager mManager;
public override IBinder OnBind (Intent intent)
{
binder = new ServiceBinder(this);
return binder;
}
public override void OnCreate()
{
base.OnCreate();
}
public override void OnDestroy()
{
base.OnDestroy();
}
#region implemented abstract members of Service
public override StartCommandResult OnStartCommand (Intent intent, StartCommandFlags flags, int startId)
{
var notificationUID = intent == null ? string.Empty : intent.Action;
var title = intent.GetStringExtra("Title");
var message = intent.GetStringExtra("Message");
if (ApplicationContext == null || this == null)
{
#if DEBUG
Console.WriteLine("CalendarAlarmService - OnStartCommand - ApplicationContext == null!");
return StartCommandResult.Sticky;
#endif
}
if (!MainActivity.AppIsInForground(this))
{
mManager = (NotificationManager)GetSystemService(NotificationService);
Intent mainActivityIntent = new Intent(this, typeof(MainActivity));
mainActivityIntent.SetAction(notificationUID);
mainActivityIntent.PutExtra("Title", title);
mainActivityIntent.PutExtra("Message", message);
mainActivityIntent.PutExtra("Notification", notificationUID);
mainActivityIntent.SetFlags(ActivityFlags.SingleTop);
Notification notification =
new Notification(Resource.Drawable.icon, "Notificacion", Java.Lang.JavaSystem.CurrentTimeMillis());
notification.Defaults |= NotificationDefaults.Sound;
mainActivityIntent.AddFlags(ActivityFlags.SingleTop | ActivityFlags.ClearTop);
PendingIntent pendingNotificationIntent =
PendingIntent.GetActivity(this, 0, mainActivityIntent, PendingIntentFlags.UpdateCurrent);
notification.Flags |= NotificationFlags.AutoCancel;
NotificationCompat.Builder builder = new NotificationCompat.Builder(
this);
notification = builder.SetContentIntent(pendingNotificationIntent)
.SetSmallIcon(Resource.Drawable.icon).SetWhen(DateTime.Now.Ticks)
.SetAutoCancel(true).SetContentTitle(title)
.SetDefaults((int)NotificationDefaults.Sound)
//.SetVibrate()
.SetContentText(message).Build();
if (!string.IsNullOrEmpty(title) && !string.IsNullOrEmpty(message))
{
mManager.Notify(0, notification);
}
}
return base.OnStartCommand (intent, flags, startId);
}
#endregion
}
public class ServiceBinder : Binder
{
CalendarAlarmService service;
public ServiceBinder(CalendarAlarmService service)
{
this.service = service;
}
public CalendarAlarmService GetCalendarService()
{
return service;
}
}
}
CalendarReceiver:
using Android.App;
using Android.Content;
namespace XXX.Droid.LocalNotifications
{
[BroadcastReceiver(Enabled = true)]
[IntentFilter(new[] { "android.intent.action.BOOT_COMPLETED" })]
public class CalendarReceiver: BroadcastReceiver
{
#region implemented abstract members of BroadcastReceiver
public override void OnReceive (Context context, Intent intent)
{
var notificationUID = intent.Action;
var title = intent.GetStringExtra ("Title");
var message = intent.GetStringExtra ("Message");
Intent service1 = new Intent(context, typeof(CalendarAlarmService));
service1.SetData(Android.Net.Uri.Parse("custom://" + notificationUID));
service1.SetAction(notificationUID);
service1.PutExtra("Title", title);
service1.PutExtra("Message", message);
context.StartService(service1);
if (MainActivity.AppIsInForground(context))
{
// App is in Foreground
GlobalMethods.RecibioNotificacionLocal(intent.Action);
}
else {
// App is in Background
//App.CrearNotificacionSQL(intent.Action);
}
App.Instance.ShowNotification(title, message);
//Toast.MakeText(Forms.Context, message ,ToastLength.Long).Show();
}
#endregion
public CalendarReceiver()
{
}
}
}
而且之后我编码,我才意识到,有一个的NuGet,可能是更好的使用:
我敢肯定,这两个插件都有同样的问题,他有通知在设备的电源循环后消失的问题。 – cvanbeek
然后使用我已发布的代码,即使设备已重新启动。 –
我知道,这更像是对原始海报的评论,插件无法解决他的问题。 – cvanbeek