Xamarin中Firebase与Azure定时通知实现方案咨询
当然可以实现指定时间触发的服药提醒通知!结合你当前用的Xamarin.Forms、Firebase+Azure Notification Hub,再配合原生平台的后台任务/本地通知机制就能搞定,我给你拆解具体的实现步骤和代码示例:
一、Xamarin.Forms 层:处理提醒设置与跨层通信
首先在Forms侧做用户设置界面,让用户输入服药时间、药物名称等信息,之后把这些数据要么存到本地数据库(比如SQLite,方便后续修改/删除),要么通过你已经在用的MessagingCenter推送给原生平台,触发定时任务注册。
举个简单的Forms代码示例:
// 用户保存提醒时的逻辑 var newReminder = new MedicationReminder { Id = Guid.NewGuid().ToString(), DrugName = "降压药", RemindTime = DateTime.Today.AddHours(8), // 用户选择的时间 IsRepeat = true // 是否每天重复 }; // 存到本地数据库,方便后续管理 await _localDbService.SaveReminderAsync(newReminder); // 通过MessagingCenter通知原生平台注册定时任务 MessagingCenter.Send(this, "RegisterMedicationReminder", newReminder);
二、Xamarin.Android 平台:用WorkManager实现可靠定时任务
Android 8+ 对后台服务限制很严,WorkManager是Google官方推荐的后台任务解决方案,能适配不同版本的系统限制,用来做定时提醒非常合适。
步骤1:创建Worker类(处理通知触发逻辑)
[Service] public class MedicationReminderWorker : Worker { public MedicationReminderWorker(Context context, WorkerParameters @params) : base(context, @params) { } public override Result DoWork() { // 获取传递的提醒数据 var reminderId = InputData.GetString("ReminderId"); var drugName = InputData.GetString("DrugName"); // 构建本地通知(Android 8+ 需要先创建通知渠道) var channelId = "MedicationReminderChannel"; var notificationManager = NotificationManagerCompat.FromApplicationContext(ApplicationContext); if (Build.VERSION.SdkInt >= BuildVersionCodes.O) { var channel = new NotificationChannel(channelId, "服药提醒", NotificationImportance.High) { Description = "定时提醒用户按时服药" }; notificationManager.CreateNotificationChannel(channel); } // 点击通知跳转回应用主页面 var intent = new Intent(ApplicationContext, typeof(MainActivity)); var pendingIntent = PendingIntent.GetActivity(ApplicationContext, 0, intent, PendingIntentFlags.UpdateCurrent | PendingIntentFlags.Immutable); var notification = new NotificationCompat.Builder(ApplicationContext, channelId) .SetContentTitle("该吃药啦!") .SetContentText($"记得服用{drugName}") .SetSmallIcon(Resource.Drawable.ic_reminder) .SetContentIntent(pendingIntent) .SetAutoCancel(true) .Build(); // 触发通知 notificationManager.Notify(Math.Abs(reminderId.GetHashCode()), notification); return Result.Success; } }
步骤2:在MainActivity中接收MessagingCenter消息,注册WorkManager任务
protected override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); // ... 其他初始化代码 // 订阅MessagingCenter,接收Forms传来的提醒数据 MessagingCenter.Subscribe<App, MedicationReminder>(this, "RegisterMedicationReminder", (sender, reminder) => { // 计算从当前时间到提醒时间的延迟 var delay = reminder.RemindTime - DateTime.Now; // 如果当前时间已过提醒时间,自动设置为明天同一时间 if (delay.TotalMilliseconds <= 0) delay = delay.AddDays(1); // 组装传递给Worker的参数 var inputData = new Data.Builder() .PutString("ReminderId", reminder.Id) .PutString("DrugName", reminder.DrugName) .Build(); // 创建定时任务:单次触发或重复触发 WorkRequest workRequest; if (reminder.IsRepeat) { // 每天重复的任务 workRequest = new PeriodicWorkRequest.Builder(typeof(MedicationReminderWorker), TimeSpan.FromDays(1)) .SetInitialDelay(delay) .SetInputData(inputData) .Build(); } else { // 单次触发的任务 workRequest = new OneTimeWorkRequest.Builder(typeof(MedicationReminderWorker)) .SetInitialDelay(delay) .SetInputData(inputData) .Build(); } // 提交任务到WorkManager WorkManager.Instance.Enqueue(workRequest); }); }
三、Xamarin.iOS 平台:用UNUserNotificationCenter实现定时本地通知
iOS对后台任务限制更严格,但系统托管的本地通知是实现定时提醒的最优方案,无需后台持续运行,由系统到点触发。
步骤1:在AppDelegate中请求通知权限并处理注册逻辑
public override bool FinishedLaunching(UIApplication app, NSDictionary options) { // 先请求用户授权通知权限 UNUserNotificationCenter.Current.RequestAuthorization(UNAuthorizationOptions.Alert | UNAuthorizationOptions.Sound, (granted, error) => { if (granted) { InvokeOnMainThread(() => UIApplication.SharedApplication.RegisterForRemoteNotifications()); } }); // 订阅MessagingCenter,接收Forms传来的提醒数据 MessagingCenter.Subscribe<App, MedicationReminder>(this, "RegisterMedicationReminder", (sender, reminder) => { SetupLocalNotification(reminder); }); return base.FinishedLaunching(app, options); } private void SetupLocalNotification(MedicationReminder reminder) { // 构建通知内容 var content = new UNMutableNotificationContent(); content.Title = "服药提醒"; content.Body = $"该服用{reminder.DrugName}了"; content.Sound = UNNotificationSound.Default; // 设置日历触发器,指定提醒的时分 var dateComponents = new NSDateComponents(); dateComponents.Hour = reminder.RemindTime.Hour; dateComponents.Minute = reminder.RemindTime.Minute; // 如果当前时间已过提醒时间,自动顺延到明天 var now = DateTime.Now; if (reminder.RemindTime.TimeOfDay < now.TimeOfDay) { dateComponents.Day = now.Day + 1; } // 创建触发器:是否重复(每天同一时间触发) var trigger = UNCalendarNotificationTrigger.CreateTrigger(dateComponents, repeats: reminder.IsRepeat); // 创建通知请求 var request = UNNotificationRequest.FromIdentifier(reminder.Id, content, trigger); // 添加到系统通知中心 UNUserNotificationCenter.Current.AddNotificationRequest(request, (error) => { if (error != null) { Console.WriteLine($"注册提醒失败:{error.LocalizedDescription}"); } }); }
四、结合Azure Notification Hub的拓展方案
如果需要跨设备同步提醒(比如用户换手机后,提醒能同步过去),可以把提醒数据存在Firebase或Azure的云端数据库里,然后用Azure Functions做定时触发器,查询到点的提醒记录,再调用Azure Notification Hub的API推送通知。
举个Azure Functions的简单示例:
[FunctionName("SendScheduledReminders")] public static async Task Run([TimerTrigger("0 */5 * * * *")]TimerInfo timer, ILogger log) { // 查询当前需要触发的提醒记录 var dueReminders = await _cloudDbService.GetDueRemindersAsync(DateTime.Now); foreach (var reminder in dueReminders) { // 调用Azure Notification Hub推送FCM通知 var hubClient = NotificationHubClient.CreateClientFromConnectionString("<你的Hub连接字符串>", "<Hub名称>"); var fcmPayload = $"{{\"notification\":{{\"title\":\"服药提醒\",\"body\":\"该吃{reminder.DrugName}啦!\"}}}}"; await hubClient.SendFcmNativeNotificationAsync(fcmPayload, reminder.UserId); } }
关键注意事项
- Android 12+ 要注意电池优化白名单,建议引导用户把应用加入白名单,避免WorkManager任务被系统杀死。
- iOS 13+ 之后,本地通知的触发必须获得用户授权,一定要在App启动时请求权限。
- 如果需要修改或删除已有的提醒,记得在原生平台对应的API中取消已注册的任务/通知,避免重复触发。
内容的提问来源于stack exchange,提问作者DCS
相关产品推荐
相关产品推荐

