iOS本地通知:UILocalNotification – iPhone手機開發技術文章 iPhone軟體開發教學課程

在去年做過一個小App,其中使用的關鍵功能就是向用戶發送本地通知,可惜當時沒有寫博客的習慣,所以沒有將對應的知識記錄下來。最近又遇到瞭該功能的使用,這一次果斷寫個博客做下有關UILocalNotification的筆記。

首先是添加一個本地通知到系統中,代碼如下:

    // 初始化本地通知對象
    UILocalNotification *notification = [[UILocalNotification alloc] init];
    if (notification) {
        // 設置通知的提醒時間
        NSDate *currentDate   = [NSDate date];
        notification.timeZone = [NSTimeZone defaultTimeZone]; // 使用本地時區
        notification.fireDate = [currentDate dateByAddingTimeInterval:5.0];
        
        // 設置重復間隔
        notification.repeatInterval = kCFCalendarUnitDay;
        
        // 設置提醒的文字內容
        notification.alertBody   = @"Wake up, man";
        notification.alertAction = NSLocalizedString(@"起床瞭", nil);
        
        // 通知提示音 使用默認的
        notification.soundName= UILocalNotificationDefaultSoundName;
        
        // 設置應用程序右上角的提醒個數
        notification.applicationIconBadgeNumber++;
        
        // 設定通知的userInfo,用來標識該通知
        NSMutableDictionary *aUserInfo = [[NSMutableDictionary alloc] init];
        aUserInfo[kLocalNotificationID] = @"LocalNotificationID";
        notification.userInfo = aUserInfo;
        
        // 將通知添加到系統中
        [[UIApplication sharedApplication] scheduleLocalNotification:notification];
    }

上面的alertBody是設備收到本地通知時橫額或鎖屏時的主要文字內容,alertActions是鎖屏時顯示的slide to後面的文字內容。例如:

repeatInterval表示通知的重復間隔,在SDK中定義如下:

vcD4KPHByZSBjbGFzcz0=”brush:java;”>@property(nonatomic) NSCalendarUnit repeatInterval; // 0 means don’t repeat
其取值主要有:

        NSCalendarUnitEra                = kCFCalendarUnitEra,
        NSCalendarUnitYear               = kCFCalendarUnitYear,
        NSCalendarUnitMonth              = kCFCalendarUnitMonth,
        NSCalendarUnitDay                = kCFCalendarUnitDay,
        NSCalendarUnitHour               = kCFCalendarUnitHour,
        NSCalendarUnitMinute             = kCFCalendarUnitMinute,
        NSCalendarUnitSecond             = kCFCalendarUnitSecond,
        NSCalendarUnitWeekday            = kCFCalendarUnitWeekday,
        NSCalendarUnitWeekdayOrdinal     = kCFCalendarUnitWeekdayOrdinal,

分別表示一個世紀、一年、一個月等等,0表示不重復。具體可以查看CFCalendar
Reference

repeatInterval的下限應該是NSCalendarUnitMinute,即每分鐘重復發送一次通知。

如果設置為NSCalendarUnitSecond,那麼消息不會重復,每秒發送一次通知,iOS系統當然不會容許這樣的存在瞭。

這裡比較不好的一點是該值不能自定義(很遺憾,NSCalendarUnit是個枚舉類型),例如你不能塞個10.0給它從而希望它每十秒重復一次。所以如果你想每20分鐘發送一次通知,一小時內發送3次,那麼隻能同時設定三個通知瞭。

上面的代碼運行後,5秒鐘之後就可以收到一個本地通知。

在收到通知後,調用程序委托中的下列方法處理:

-(void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification{
    NSLog(@"Application did receive local notifications");
    
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Hello" message:@"welcome" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
    [alert show];
}

註意這個方法隻有在程序啟動之後才會執行,因此當程序處於後臺時,該方法不會執行。

有一點需要註意,如果我們的應用程序給系統發送的本地通知是周期性的,那麼即使把程序刪瞭重裝,之前的本地通知在重裝時依然存在(沒有從系統中移除)。例如,我們在viewDidLoad方法中啟動添加本地通知的方法,多跑幾次,然後把程序在模擬器中刪除,再重新跑,並用下列方法輸出所有的本地通知:

    NSArray *localNotifications = [[UIApplication sharedApplication] scheduledLocalNotifications];
    NSLog(@"%@", localNotifications);

控制臺輸出:

2014-03-14 15:46:37.145 LocalNotificationDemo[4419:60b] (
    "{fire date = Friday, March 14, 2014 at 3:38:16 PM China Standard Time, time zone = Asia/Chongqing (GMT+8) offset 28800, repeat interval = NSDayCalendarUnit, repeat count = UILocalNotificationInfiniteRepeatCount, next fire date = Saturday, March 15, 2014 at 3:38:16 PM China Standard Time, user info = {\n    ClockID = LocalNotificationID;\n}}",
    "{fire date = Friday, March 14, 2014 at 3:44:45 PM China Standard Time, time zone = Asia/Chongqing (GMT+8) offset 28800, repeat interval = NSDayCalendarUnit, repeat count = UILocalNotificationInfiniteRepeatCount, next fire date = Saturday, March 15, 2014 at 3:44:45 PM China Standard Time, user info = {\n    ClockID = LocalNotificationID;\n}}",
    "{fire date = Friday, March 14, 2014 at 3:44:55 PM China Standard Time, time zone = Asia/Chongqing (GMT+8) offset 28800, repeat interval = NSDayCalendarUnit, repeat count = UILocalNotificationInfiniteRepeatCount, next fire date = Saturday, March 15, 2014 at 3:44:55 PM China Standard Time, user info = {\n    ClockID = LocalNotificationID;\n}}",
    "{fire date = Friday, March 14, 2014 at 3:45:13 PM China Standard Time, time zone = Asia/Chongqing (GMT+8) offset 28800, repeat interval = NSDayCalendarUnit, repeat count = UILocalNotificationInfiniteRepeatCount, next fire date = Saturday, March 15, 2014 at 3:45:13 PM China Standard Time, user info = {\n    ClockID = LocalNotificationID;\n}}",
    "{fire date = Friday, March 14, 2014 at 3:45:29 PM China Standard Time, time zone = Asia/Chongqing (GMT+8) offset 28800, repeat interval = NSDayCalendarUnit, repeat count = UILocalNotificationInfiniteRepeatCount, next fire date = Saturday, March 15, 2014 at 3:45:29 PM China Standard Time, user info = {\n    ClockID = LocalNotificationID;\n}}",
    "{fire date = Friday, March 14, 2014 at 3:46:28 PM China Standard Time, time zone = Asia/Chongqing (GMT+8) offset 28800, repeat interval = NSDayCalendarUnit, repeat count = UILocalNotificationInfiniteRepeatCount, next fire date = Saturday, March 15, 2014 at 3:46:28 PM China Standard Time, user info = {\n    ClockID = LocalNotificationID;\n}}"
)

可以看到之前發送的本地通知一直滯留在系統中。

不隻是模擬器,在iOS設備上也是這樣,博主之前的App在設備上重裝時以前的本地通知會繼續發送。

因此我們需要取消通知的方法,當然該對象也會在scheduledLocalNotifications數組中移除。

取消方法分為兩種。

第一種比較暴力,直接取消所有的本地通知:

[[UIApplication sharedApplication] cancelAllLocalNotifications];

這個適合在App重裝時第一次啟動的時候,或還原程序默認設置等場合下使用。

第二種方法是針對某個特定通知的:

- (void)cancelLocalNotification:(UILocalNotification *)notification NS_AVAILABLE_IOS(4_0);

這時就需要通知有一個標識,這樣我們才能定位是哪一個通知。可以在notification的userInfo(一個字典)中指定。

例如:

-(void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification{
    NSLog(@"Application did receive local notifications");
    
    // 取消某個特定的本地通知
    for (UILocalNotification *noti in [[UIApplication sharedApplication] scheduledLocalNotifications]) {
        NSString *notiID = noti.userInfo[kLocalNotificationID];
        NSString *receiveNotiID = notification.userInfo[kLocalNotificationID];
        if ([notiID isEqualToString:receiveNotiID]) {
            [[UIApplication sharedApplication] cancelLocalNotification:notification];
            return;
        }
    }
    
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Hello" message:@"welcome" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
    [alert show];
}

最後建議本地通知不要發得太頻繁,不然用戶會覺得非常的煩。

參考的文章和資料:

IOS本地通知

CFCalendar
Reference

iOS: 枚舉類型 enum,NS_ENUM,NS_OPTIONS

發佈留言