我创建了一个iOS自定义日历,尝试使用badge number来显示日期数量,但是在一天过去之后数字没有改变,我的意思是它们应该实时更新。这是我的代码:我需要像天气实况应用程序一样的东西,这个应用程序不发送任何推送通知!
int a = [DateComponents showDay];
[UIApplication sharedApplication].applicationIconBadgeNumber = a ;
目前在iOS上做到这一点并不容易。虽然用户偶尔打开应用程序,但您可以接近,但无法每天可靠地更新徽章 除非用户偶尔打开应用。
您需要使用UILocalNotification
。您可以创建和安排“静默”通知,以此方式更新应用程序徽章,而不会提醒用户或播放警报声音:
UILocalNotification* notification = [[UILocalNotification alloc] init];
notification.fireDate = [NSDate dateWithTimeIntervalSinceNow:seconds];
notification.timeZone = [NSTimeZone systemTimeZone];
notification.alertBody = nil;
notification.soundName = nil;
notification.applicationIconBadgeNumber = dayTomorrow;
[[UIApplication sharedApplication] scheduleLocalNotification:notification];
[notification release];
dayTomorrow
是明天的日期,以整数形式表示。而seconds
是某个时间间隔,例如距离午夜的时间间隔。当此通知被发送时,用户将不会收到任何警报或声音,但应用程序图标上的徽章应更新为新值。您可以使用repeatInterval
属性使此通知每天重复,但问题在于,第二天您需要将dayTomorrow
更改为另一个值,之后的日子也是如此。但是,重复的通知始终具有相同的applicationIconBadgeNumber
值。
因此,我认为实现与您想要的内容接近的唯一方法是安排多个本地通知 - 您可以提前安排最多64个通知 - 每个通知相隔一天,并将那一天的值设置为applicationIconBadgeNumber
。这些通知必须是非重复的,因此请确保将repeatInterval
设置为nil(或者不设置它,因为nil是默认值)。假设所有这些通知都可靠地被iOS传递,您将能够在不打扰用户的情况下静默更新徽章号码长达64天。在那之后,徽章将停止更新...除非您在此期间成功安排更多通知 - 即当用户打开应用程序时。您可以尝试在应用程序启动时取消所有现有的预定通知:
[[UIApplication sharedApplication] cancelAllLocalNotifications];
然后循环提前64天,每天午夜定时一个通知,并使用正确的月份为 applicationIconBadgeNumber
属性更新徽章图标。只要用户每64天至少打开一次您的应用程序,您就可以保持徽章图标最新状态。如果您预计您的应用程序用户经常打开应用程序(例如,每天多次),那么优化可能是检查已安排的现有通知数量,然后取消它们并创建64个新通知,如下所示:
if ([[[UIApplication sharedApplication] scheduledLocalNotifications] count] < 10)
{
//there are 10 or fewer days' worth of notifications scheduled, so create and
//schedule more here, up to 64 in total.
}
需要注意以下几点:
application:didReceiveLocalNotification:
方法,但徽章图标不会更新。因此,为了考虑到这种情况,我建议每次应用程序启动时(或从后台返回前台)将徽章图标更新为当天的日期。编辑:
以下是一个代码片段,用于取消任何现有的本地通知并在将来的64个午夜计划通知,并将正确的日期指定为徽章号码:
[[UIApplication sharedApplication] cancelAllLocalNotifications];
NSCalendar* calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents* components = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate:[NSDate date]];
[components setHour:0];
[components setMinute:0];
[components setSecond:0];
NSDate* midnightToday = [calendar dateFromComponents:components];
const int SECONDS_PER_DAY = 60 * 60 * 24;
for (int i = 1; i <= 64; i++)
{
NSDate* futureDate = [midnightToday dateByAddingTimeInterval:i * SECONDS_PER_DAY];
NSDateComponents* components = [calendar components:NSDayCalendarUnit fromDate:futureDate];
UILocalNotification* notification = [[UILocalNotification alloc] init];
notification.fireDate = futureDate;
notification.timeZone = [NSTimeZone systemTimeZone];
notification.alertBody = nil;
notification.soundName = nil;
notification.applicationIconBadgeNumber = components.day;
//NSLog(@"futureDate: %@", [NSDateFormatter localizedStringFromDate:futureDate dateStyle:NSDateFormatterMediumStyle timeStyle:NSDateFormatterMediumStyle]);
//NSLog(@"notification: %@", notification);
[[UIApplication sharedApplication] scheduleLocalNotification:notification];
[notification release];
}
[calendar release];
这里发生的情况是:
[NSDate date]
获取今天的日期,然后将其拆分成我们想要保留的部分(年、月、日),并将时间组件(小时、分钟、秒钟)设置为午夜。这给了我们midnightToday
。midnightToday
并加上每天的秒数乘以我们希望日期在未来多少天内的天数来实现。我们使用此日期安排本地通知。NSDateComponents
将未来日期分解为我们感兴趣的组件 - 在这种情况下,只需指定NSDayCalendarUnit
即可得到日期。然后,我们可以将applicationIconBadgeNumber
设置为components.day
。请注意,这可能仅适用于使用格雷戈里历(西式)的用户 - 根据您的市场,您可能需要考虑世界各地使用的其他日历类型,并支持这些类型。
SECONDS_PER_DAY
显示的是明天,而i * SECONDS_PER_DAY
则是后天,所以我将其更改为:60 * 60
;并删除了i *
,因为我的日历是波斯日历,所以我正在等待明天看到更新的徽章数量。 - iOS.LoverfutureDate
时要小心,因为我认为它总是显示为GMT而不是您自己的时区。但是,如果您在设置了fireDate
之后检查通知,它将显示为您所在时区的正确时间。所以请确保您检查了这一点。我还在我的设备上进行了设置,并耐心地等待明天看是否所有更新都正确 :) - Rob B您应该可以使用UILocalNotification来完成。
我不确定是否可以将其设置为每天自动重复一次,但您可能可以发送多个通知以模拟该效果。
您是如何调用此方法的?如果您设置一个定时器每x秒运行一次此代码,它将在下一个定时器触发时更新。