2017-10-19 27 views
1

我已经为我的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); 
     } 
    } 
} 
} 

回答

0

你必须有一个服务和广播接收器这样的事情(这是一个古老的代码):

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,可能是更好的使用:

https://github.com/edsnider/LocalNotificationsPlugin

https://github.com/aritchie/notifications

+0

我敢肯定,这两个插件都有同样的问题,他有通知在设备的电源循环后消失的问题。 – cvanbeek

+0

然后使用我已发布的代码,即使设备已重新启动。 –

+1

我知道,这更像是对原始海报的评论,插件无法解决他的问题。 – cvanbeek