应用程序启动与否时发出通知铃声(Xamarin.Forms)

Posted

技术标签:

【中文标题】应用程序启动与否时发出通知铃声(Xamarin.Forms)【英文标题】:Make a notification ring when App launched or not (Xamarin.Forms) 【发布时间】:2017-10-28 09:28:42 【问题描述】:

我正在使用 依赖服务 DependencyService.Get<ISetAlarm>().SetAlarm(hour,min,"Diabetics App","Hello i remind you to take medicine");,它连接到我的 AlarmReceiverAlarmImplementation 类, 问题是:

当我以任何形式放置 依赖服务 代码时,通知 只有当我启动该表单时,当我输入onStart,onSleep 时才会出现 通知仅在这种状态下出现的方法,我该怎么做 发出通知的应用程序就像一个真正的警报,当它是 启动与否?

另外:

AlarmReceiver 类

using System;
using android.App;
using Android.Content;
using Android.Media;
using Android.Support.V4.App;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using Android.Widget;
using Diabetes.localDB;
using Xamarin.Forms;

namespace Diabetes.Droid

    [BroadcastReceiver]
    [IntentFilter(new string[]  "android.intent.action.BOOT_COMPLETED" , Priority = (int)IntentFilterPriority.LowPriority)]
    public class AlarmReceiver : BroadcastReceiver
    

        public override void OnReceive(Context context, Intent intent)
        
            if (intent.Action.Equals("android.intent.action.BOOT_COMPLETED"))
            
            var message = intent.GetStringExtra("message");
            var title = intent.GetStringExtra("title");



            //Show toast here
            //Toast.MakeText(context, "Hello it's me ", ToastLength.Short).Show();
            var extras = intent.Extras;

            if (extras != null && !extras.IsEmpty)
            
                NotificationManager manager_ = context.GetSystemService(Context.NotificationService) as NotificationManager;
                var notificationId = extras.GetInt("NotificationIdKey", -1);
                if (notificationId != -1)
                
                    manager_.Cancel(notificationId);
                
            

            //Create intent for action 1 (TAKE)
            var actionIntent1 = new Intent();
            actionIntent1.SetAction("ARCHIVE");
            var pIntent1 = PendingIntent.GetBroadcast(context, 0, actionIntent1, PendingIntentFlags.CancelCurrent);

            //Create intent for action 2 (REPLY)
            var actionIntent2 = new Intent();
            actionIntent2.SetAction("REPLY");
            var pIntent2 = PendingIntent.GetBroadcast(context, 0, actionIntent2, PendingIntentFlags.CancelCurrent);

            Intent resultIntent = context.PackageManager.GetLaunchIntentForPackage(context.PackageName);

            var contentIntent = PendingIntent.GetActivity(context, 0, resultIntent, PendingIntentFlags.CancelCurrent);

            var pending = PendingIntent.GetActivity(context, 0,
                resultIntent,
                PendingIntentFlags.CancelCurrent);
            //seting an alarm
            MedicationDatabase db = new MedicationDatabase();
            var alarm_list = db.GetAlarmList();
            //Debug.WriteLine(" Time -- : "+ m.ToString());


            // Instantiate the Big Text style:
            Notification.BigTextStyle textStyle = new Notification.BigTextStyle();


            var builder =
                new Notification.Builder(context)
                                .AddAction(Resource.Drawable.tick_notify, "ARCHIVE", pIntent1)
                                .AddAction(Resource.Drawable.cancel_notify, "REPLY", pIntent2)
                                .SetSmallIcon(Resource.Drawable.ic_launcher)
                                .SetContentTitle("Diabetics Reminder")
                                .SetDefaults(NotificationDefaults.Sound)
                                .SetStyle(new Notification
                                .BigTextStyle()
                                .SetSummaryText("")
                                .SetBigContentTitle(title)
                                .BigText(message)
             ).SetDefaults(NotificationDefaults.All);

            builder.SetContentIntent(pending);

            var notification = builder.Build();


            var manager = NotificationManager.FromContext(context);
            manager.Notify(10010, notification);
        
        
    

    [BroadcastReceiver]
    [IntentFilter(new string[]  "ARCHIVE", "REPLY" )]
    public class CustomActionReceiver : BroadcastReceiver
    
        public override void OnReceive(Context context, Intent intent)
        

            switch (intent.Action)
            
                case "ARCHIVE":
                    try
                    
                        MedicationDatabase db = new MedicationDatabase();
                        db.addtracktaken("true");
                        Toast.MakeText(context, "DOSAGE TAKEN", ToastLength.Short).Show();
                    
                    catch (Exception e)
                    
                        Debug.WriteLine(e.StackTrace);
                    
                    break;
                case "REPLY":
                    try
                    
                        Toast.MakeText(context, "ARCHIVE", ToastLength.Short).Show();
                        MedicationDatabase db = new MedicationDatabase();
                        db.addtrackmissed("true");
                        Toast.MakeText(context, "DOSAGE MISSED", ToastLength.Short).Show();
                    
                    catch (Exception e)
                    
                        Debug.WriteLine(e.StackTrace);
                    
                    break;
            

            var extras = intent.Extras;

            if (extras != null && !extras.IsEmpty)
            
                NotificationManager manager = context.GetSystemService(Context.NotificationService) as NotificationManager;
                var notificationId = extras.GetInt("NotificationIdKey", -1);
                if (notificationId != -1)
                
                    manager.Cancel(notificationId);
                
            
        
    

AlarmImplementation 类

[assembly: Xamarin.Forms.Dependency(typeof(SetAlarmImplementation))]
namespace Diabetes.Droid

    public class SetAlarmImplementation : ISetAlarm
    

        public void SetAlarm(int hour, int minute, string title, string message, string)
        

            MedicationDatabase db = new MedicationDatabase();
            var alarm_list = db.GetAlarmList();
            //Debug.WriteLine(" Time -- : "+ m.ToString());




            Intent myintent = new Intent(Xamarin.Forms.Forms.Context, typeof(AlarmReceiver));
            myintent.PutExtra("message", message);
            myintent.PutExtra("title", title);
            PendingIntent pendingintent = PendingIntent.GetBroadcast(Xamarin.Forms.Forms.Context, 0, myintent, PendingIntentFlags.UpdateCurrent);

            Java.Util.Date date = new Java.Util.Date();
            Java.Util.Calendar cal = Java.Util.Calendar.Instance;
            cal.TimeInMillis = Java.Lang.JavaSystem.CurrentTimeMillis();
            cal.Set(Java.Util.CalendarField.HourOfDay, hour);
            cal.Set(Java.Util.CalendarField.Minute, minute);
            cal.Set(Java.Util.CalendarField.Second, 0);
            //  PendingIntent pendingIntent = PendingIntent.GetBroadcast(this, 0, alarmIntent, PendingIntentFlags.UpdateCurrent);
            AlarmManager alarmManager = Xamarin.Forms.Forms.Context.GetSystemService(Android.Content.Context.AlarmService) as AlarmManager;
            alarmManager.Set(AlarmType.RtcWakeup, cal.TimeInMillis, pendingintent);
        
    

编辑:

这是我的新更新

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Diabetes.localDB;
using Diabetes.Main;

namespace Diabetes.Droid

    [Activity(Label = "MainApplication")]
    public class MainApplication : Activity
    
        ISetAlarm alarmService;
        MedicationDatabase db = new MedicationDatabase();

        public MainApplication()

        
        public MainApplication(IntPtr handle, JniHandleOwnership transer) : base(handle, transer)
        
        

        protected override void OnCreate(Bundle savedInstanceState)
        
            base.OnCreate(savedInstanceState);
            alarmService = new SetAlarmImplementation();
            //Get list of stored time from Sqlite
            var alarm_list = db.GetAlarmList();
            //Debug.WriteLine(" Time -- : "+ m.ToString());
            var message = "Hello Its I remind you to take insulin";
            var title = "Diabetics App";
            foreach (var list in alarm_list)
            
                var hour = Int32.Parse(list.Substring(0, 2));
                var minute = Int32.Parse(list.Substring(3, 2));
                alarmService.SetAlarm(hour, minute, title,message);
                // Create your application here
            
        
    

这就是我所做的,但是现在当我设置没有通知的时间时,就好像我必须以某种方式触发它。

我想已经接近答案了,我需要更多指导谢谢。

编辑 2:

查看 My Sqlite DB 类:

using System;
using System.Collections.Generic;
using System.Linq;
using SQLite.Net;
using Xamarin.Forms;

namespace Diabetes.localDB

    public class MedicationDatabase
    
        private SQLiteConnection _connection;

        public MedicationDatabase()
        

            _connection = DependencyService.Get<ISQLite>().GetConnection();
            _connection.CreateTable<Medication>();
            _connection.CreateTable<SetReminder>();
            // _connection.CreateTable<Track>();
            _connection.CreateTable<TrackMissed>();
            _connection.CreateTable<TrackTaken>();
            _connection.CreateTable<LoginModel>();


        
        public void AddDetails(string username, string alarm_time, string units, string insulin_type, string unique_id, string status)
        

            _connection.Query<Medication>("Insert into [Medication] (username, alarm_time, units,insulin_type,unique_id,status) values" +
                                          "('" + username + "','" + alarm_time + "','" + units + "','" + insulin_type + "','" + unique_id + "','" + status + "')");

        


        public void AddReminder(string username, string alarm_time,
                             string units, string insulin_type, string count_times)
        

            _connection.Query<SetReminder>("Insert into [SetReminder] (username, alarm_time, units,insulin_type,count_times) values" +
                                          "('" + username + "','" + alarm_time + "','" + units
                                           + "','" + insulin_type + "','" + count_times + "')");
        

        public IEnumerable<Medication> AllMedicationResults()
        
            return (from t in _connection.Table<Medication>()
                    select t).ToList();
        

        public IEnumerable<SetReminder> AllReminders()
        
            return (from t in _connection.Table<SetReminder>()
                    select t).ToList();
        

        public IEnumerable<string> GetAlarmList()
        
            return (from t in _connection.Table<Medication>()
                    select t.alarm_time).ToList();
        


        /* public string AlarmSample()
             return (_connection.Table<SetReminder>().Select(r => r.)
            .AsEnumerable()
                      .Select(r => r.Substring(1, r.Length - 2).Split(','))).ToList().ToString()
                                                                            ;        */

        public IEnumerable<string> GetUnitsList()
        
            return (from t in _connection.Table<Medication>()
                    select t.units).ToList();
        

        public void DeleteAlarm()
        
            _connection.DeleteAll<SetReminder>();
        


        public void DeleteTime(int id)
        

            _connection.Delete<Medication>(id);
        

        public void DeleteAllTime()
        
            _connection.DeleteAll<Medication>();
        

        // Tracking table 
        public void addtracktaken(string taken)
        

            _connection.Query<TrackTaken>("Insert into [TrackTaken] (taken) values" +
                                          "('" + taken + "')");
        

        public void addtrackmissed(string missed)
        

            _connection.Query<TrackMissed>("Insert into [TrackMissed] (missed) values" +
                                           "('" + missed + "')");
        

        public int GetTracksTakenNos()
        
            return (from t in _connection.Table<TrackTaken>()
                    select t.taken).Count();
        

        public int GetTracksMissedNo()
        
            return (from t in _connection.Table<TrackMissed>()
                    select t.missed).Count();
        

        //Loging in 
        public void addUser(string username, string logged)
        

            _connection.Query<LoginModel>("Insert into [LoginModel] (username,LoggedIn) values" +
                                          "('" + username + "', '" + logged + "')");
        

        public void DeleteUsers()
        
            _connection.DeleteAll<LoginModel>();
        

        public string LoggedInStatus()
        
            List<LoginModel> list = _connection.Query<LoginModel>("Select LoggedIn From [LoginModel] where ID=1");
            return list[0].LoggedIn;

        

        public string GetUserName()
        
            List<LoginModel> list = _connection.Query<LoginModel>("Select username From [LoginModel] where ID=1");
            return list[0].username;

        

    

还有界面:

namespace Diabetes.localDB

    public interface ISQLite
    
        SQLiteConnection GetConnection();
    

【问题讨论】:

你试过这个插件:nuget.org/packages/Xam.Plugins.Notifier 吗?它已经为您处理了 AlarmManager 并提供了 PCL 实现。 是的@RodrigoE.,我试过了,但它错过了很多功能,这就是我最终使用依赖服务的原因 @IdrisStack 你是说当你打电话给.SetAlarm时通知会立即触发吗? 是的,我喜欢让 App 像真正的警报一样做出反应,我应该使用 onSleep、onpause 等特殊方法来实现这一点,因为我试图将它放在 App 中.cs,但是当我启动应用程序时会弹出通知,当到达预定时间时它不能弹出 它也会出现在我调用.SetAlarm的页面上 【参考方案1】:

首先,不要使用 DependencyService,因为它依赖于 Xamarin Forms 初始化,因此它只会在打开应用程序时工作。当应用程序关闭时,您不能执行任何与 Xamarin Forms 相关的调用,因为此时 MainActivity 不可用并且 Xamarin Forms 会在其上中继。

建议改为执行以下操作:

1.创建一个Android应用类

2.在那里创建警报服务的实例。

3.设置闹钟

 [Application]
 public class MainApplication : Application
 
     ISetAlarm alarmService;
     public MainApplication(IntPtr handle, JniHandleOwnership transer) :base(handle, transer)
     
     

     public override void OnCreate()
     
        base.OnCreate();
        alarmService = new SetAlarmImplementation();
        alarmService.SetAlarm(hour,min,"Diabetics App","Hello i remind you to take medicine");

     

【讨论】:

非常感谢@Rendy 的回复,我编辑了我的帖子,但现在我没有收到任何通知 应用程序关闭或打开时没有收到? 顺便说一句,您修改的代码是错误的,您一直使用 Activity 来初始化警报,您刚刚将其重命名为 MainApppication。 仔细查看我的代码和你的代码,你会发现你使用 [Activity] 属性的差异我使用的是 [Application] 属性。您从 Activity 类继承,我的继承自 Application 类。 我现在对其进行了编辑,但仍在与 TargetInvocation Exception 斗争,它需要 global::Xamarin.Forms.Forms.Init(this);,我正在尝试输入它,但有一些错误【参考方案2】:

在您的应用程序类的 OnCreate 方法上启动一个粘性服务,这样即使应用程序关闭,该服务也会使应用程序保持活动状态并且您仍然可以获得通知。

[Application]
public class MainApplication : Application

    public static Context AppContext;
    public MainApplication(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
    
    

    public override void OnCreate()
    
        base.OnCreate();
        AppContext = this.ApplicationContext;

        StartService();
    

    public static void StartService()
    
        AppContext.StartService(new Intent(AppContext, typeof(AppStickyService)));
        if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.Kitkat)
        

            PendingIntent pintent = PendingIntent.GetService(AppContext, 0, new Intent(AppContext, typeof(AppStickyService)), 0);
            AlarmManager alarm = (AlarmManager)AppContext.GetSystemService(Context.AlarmService);
            alarm.Cancel(pintent);
        
    

    public static void StopService()
    
        AppContext.StopService(new Intent(AppContext, typeof(AppStickyService)));
                    if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.Kitkat)
        
            PendingIntent pintent = PendingIntent.GetService(AppContext, 0, new Intent(AppContext, typeof(AppStickyService)), 0);
            AlarmManager alarm = (AlarmManager)AppContext.GetSystemService(Context.AlarmService);
            alarm.Cancel(pintent);
        
    


创建一个粘性服务类:

[Service]
public class AppStickyService : Service

    public override void OnCreate()
    
        base.OnCreate();

        System.Diagnostics.Debug.WriteLine("Sticky Service - Created");
    

    public override StartCommandResult OnStartCommand(Android.Content.Intent intent, StartCommandFlags flags, int startId)
    
        System.Diagnostics.Debug.WriteLine("Sticky Service - Started");
        return StartCommandResult.Sticky;
    

    public override Android.OS.IBinder OnBind(Android.Content.Intent intent)
    
        System.Diagnostics.Debug.WriteLine("Sticky Service - Binded");
        return null;
    

    public override void OnDestroy()
    
        System.Diagnostics.Debug.WriteLine("Sticky Service - Destroyed");
        base.OnDestroy();
    

【讨论】:

请注意,调试时不应关闭应用程序。您可以停止应用程序,然后重新打开并再次关闭。但在调试过程中永远不要关闭它,因为 Android 不能很好地处理这种情况。 我已经试过这个代码,我首先放置alarmService.SetAlarm(hour,min,"Diabetics App","Hello i remind you to take medicine"); 然后StartService()它在设定的时间到达时崩溃了,我也以相反的方式进行,没有任何结果,我应该把所有的警报StartService()方法中的实现代码? 请接受我在 Facebook 上的好友请求 我的名字是 Lutaaya Huzaifah Idris 我不知道我会如何感谢你,但是,你的回答对我帮助很大@Rendy,你应该喝一杯 capucino

以上是关于应用程序启动与否时发出通知铃声(Xamarin.Forms)的主要内容,如果未能解决你的问题,请参考以下文章

错误:当有来自 firebase 的通知时,我没有收到铃声

无法为通知android设置铃声

如何使用 Apple 制作的铃声作为本地通知? (迅速)

xamarin.ios 本地通知推送

从我的 iOS 应用程序中,如何设置铃声(默认电话)、闹钟(默认闹钟)、默认通知、联系人..? [关闭]

在本地通知上发送带有自定义声音的触觉