如何在指定日期后停止iOS本地定时通知触发?
首先,你当前的逻辑在APP后台/被杀死后失效,核心原因是WillPresentNotification方法只有当APP处于前台时才会被调用——当APP在后台或者完全被杀死时,系统会直接展示通知,不会走这个回调,所以你在里面的移除通知逻辑根本不会执行。
另外,UNCalendarNotificationTrigger本身不支持直接设置截止日期,重复触发的通知会一直执行下去,除非你主动移除它。下面给你几个可行的解决思路:
1. 最精准的方案:创建多个单次触发的通知
既然你的日期范围是固定的(2018.6.1到2018.6.28),每天14点触发,那你可以提前计算出这个范围内所有符合条件的日期,给每个日期创建一个单次触发的UNCalendarNotificationTrigger(repeat: false),而不是一个重复触发的通知。这样到2018.6.28之后,就没有待处理的通知请求了,自然不会再触发。
代码示例:
var content = new UNMutableNotificationContent(); content.Title = "Title"; content.Subtitle = "Subtitle"; content.Body = "Body"; content.Badge = 1; content.CategoryIdentifier = categoryID; content.Sound = UNNotificationSound.Default; // 定义日期范围 DateTime startDate = new DateTime(2018, 6, 1); DateTime endDate = new DateTime(2018, 6, 28); // 遍历每天,创建单个通知 for (DateTime date = startDate; date <= endDate; date = date.AddDays(1)) { var components = new NSDateComponents { Year = date.Year, Month = date.Month, Day = date.Day, Hour = 14 }; // 创建单次触发的触发器 var trigger = UNCalendarNotificationTrigger.CreateTrigger(components, false); // 每个通知用唯一的requestID,比如加上日期 string requestID = $"notificationRequest_{date:yyyyMMdd}"; var request = UNNotificationRequest.FromIdentifier(requestID, content, trigger); UNUserNotificationCenter.Current.AddNotificationRequest(request, (err) => { if (err != null) { Console.WriteLine($"Error scheduling {requestID}: {err}"); } else { Console.WriteLine($"Scheduled {requestID}"); } }); } // 设置代理处理点击事件 UNUserNotificationCenter.Current.Delegate = new CustomUNUserNotificationCenterDelegate();
这个方案的优势是完全精准,不需要后续维护,系统会自动处理每个日期的通知,过期后没有残留的重复通知。
2. 后台刷新方案(适合动态变化的日期范围)
如果你的日期范围不是固定的,或者需要动态调整,那可以使用后台刷新任务来定期检查当前日期是否超过结束日期,如果超过就移除重复的通知请求。
步骤:
- 在
Info.plist中开启Background Modes的Background fetch权限。 - 注册后台刷新任务,比如每天触发一次:
UIApplication.SharedApplication.SetMinimumBackgroundFetchInterval(UIApplication.BackgroundFetchIntervalMinimum);
- 在
AppDelegate的PerformFetch方法中检查日期并移除通知:
public override void PerformFetch(UIApplication application, Action<UIBackgroundFetchResult> completionHandler) { DateTime endDate = new DateTime(2018, 6, 28, 14, 0, 0); if (DateTime.Now >= endDate) { // 移除重复通知的请求 var requests = new string[] { "notificationRequest" }; UNUserNotificationCenter.Current.RemovePendingNotificationRequests(requests); } completionHandler(UIBackgroundFetchResult.NoData); }
不过这个方案的缺点是后台刷新的触发时间不固定,系统会根据APP的使用频率等因素决定何时触发,可能无法做到在2018.6.28下午2点精准停止,但对于大多数场景来说足够了。
3. 关于ComponentsFromDateToDate的错误使用
你之前尝试的ComponentsFromDateToDate方法,它的作用是计算两个日期之间的时间差(比如相差多少秒、分钟等),并不是用来设置通知的触发条件的,所以这个方法根本无法帮你限制通知的触发范围,你的用法确实不对,这个思路走不通。
总结
如果你的日期范围是固定的,优先选择方案一,精准且无需后续维护;如果日期范围需要动态调整,再考虑方案二。UNCalendarNotificationTrigger本身没有截止日期的设置项,必须通过上述两种方式来实现你的需求。
内容的提问来源于stack exchange,提问作者VKP

