iOS本地推送通知的簡單封裝(定時提醒速那、重復提醒)

實現快捷創(chuàng)建簡單的定時重復提醒推送功能。

主要實現原理

iOS10及以上

1.獲取通知權限

iOS10及以上要先請求通知權限

UNUserNotificationCenter * center = [UNUserNotificationCenter currentNotificationCenter];
    //請求獲取通知權限(角標尿背,聲音端仰,彈框)
    [center requestAuthorizationWithOptions:(UNAuthorizationOptionBadge |
                                             UNAuthorizationOptionSound |
                                             UNAuthorizationOptionAlert)
                          completionHandler:^(BOOL granted, NSError * _Nullable error) {
        if (granted) {
            //獲取用戶是否同意開啟通知
            NSLog(@"開啟通知成功!");

        }
    }];
    

2.創(chuàng)建通知

UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
    content.title = attribute[ZBNotificationAlertTitle];
//    content.subtitle = @"本地通知副標題";
    content.body = @"body";
    //角標數量
    content.badge = @1;
    content.userInfo = userInfo;

    //設置通知聲音
    UNNotificationSound *sound = [UNNotificationSound defaultSound];
    content.sound = sound;
    

創(chuàng)建 UNNotificationRequest :

//設置時間容器:傳人date中所有時間元素放入時間容器
NSDateComponents * components = [[NSCalendar currentCalendar]
                                     components:NSCalendarUnitYear |
                                     NSCalendarUnitMonth |
                                     NSCalendarUnitWeekday |
                                     NSCalendarUnitDay |
                                     NSCalendarUnitHour |
                                     NSCalendarUnitMinute |
                                     NSCalendarUnitSecond
                                     fromDate:date];
//設置UNCalendarNotificationTrigger
//repeats: 設置是否重復
UNCalendarNotificationTrigger * trigger = [UNCalendarNotificationTrigger 
                                            triggerWithDateMatchingComponents:components 
                                            repeats:repeat];
//設置UNNotificationRequest
//identifer:設置通知標識符或者說通知名字
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:identifer content:content trigger:trigger];

3.添加通知

//把通知加到UNUserNotificationCenter, 到指定觸發(fā)點會被觸發(fā)
[[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
    if (error) {
        NSLog(@"通知添加失敗:%@",error);
    } else {
        NSLog(@"通知添加成功");
    }
}];

4.重復提醒

如果repeats為YES時為重復提醒
約定在特定時間提醒時我們用時間容器來實現

NSDateComponents * components = [[NSCalendar currentCalendar]
                                     components:NSCalendarUnitYear |
                                     NSCalendarUnitMonth |
                                     NSCalendarUnitWeekday |
                                     NSCalendarUnitDay |
                                     NSCalendarUnitHour |
                                     NSCalendarUnitMinute |
                                     NSCalendarUnitSecond
                                     fromDate:date];
                                     

比如設置一個每天都提醒的推送,傳入的時間設置為:

NSDateFormatter * formatter = [[NSDateFormatter alloc]init];
[formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
NSDate * date = [formatter dateFromString:@"2019-01-01 08:00:00"];

每天8點 進行推送提醒的 時間容器 為:

NSDateComponents * components = [[NSCalendar currentCalendar]
                                     components:NSCalendarUnitHour |
                                                NSCalendarUnitMinute |
                                                NSCalendarUnitSecond
                                     fromDate:date];
                                     

每周二8點 (19年1月1號為周二) 進行推送提醒的 時間容器 為:

NSDateComponents * components = [[NSCalendar currentCalendar]
                                     components:NSCalendarUnitWeekday |
                                     NSCalendarUnitHour |
                                     NSCalendarUnitMinute |
                                     NSCalendarUnitSecond
                                     fromDate:date];
                                     

每月1號8點 進行推送提醒的 時間容器 為:

NSDateComponents * components = [[NSCalendar currentCalendar]
                                     components:NSCalendarUnitDay |
                                     NSCalendarUnitHour |
                                     NSCalendarUnitMinute |
                                     NSCalendarUnitSecond
                                     fromDate:date];
                                     

每年1月1號8點 進行推送提醒的 時間容器 為:

NSDateComponents * components = [[NSCalendar currentCalendar]
                                     components:NSCalendarUnitMonth |
                                     NSCalendarUnitDay |
                                     NSCalendarUnitHour |
                                     NSCalendarUnitMinute |
                                     NSCalendarUnitSecond
                                     fromDate:date];
                                     

以此類推..
如果有需求是要 周一到周五的每天8點 提醒時田藐,我的做法是用for循環(huán)創(chuàng)建5個通知:

//因為周日是一星期第一天榆俺,1代表周日,所以周一從2開始
for (NSInteger i = 2; i <= 6; i++) {
//這里時間容器創(chuàng)建和以上每周提醒的一樣坞淮,省略。
        components.weekday = i;
        
//然后用這個components去添加通知就可以實現重復通知了
}

5.取消通知

//找到要取消的通知名字
NSMutableArray * names = [[NSMutableArray alloc]initWithObjects:notificationName, nil];
//批量取消這些通知
[[UNUserNotificationCenter currentNotificationCenter] removePendingNotificationRequestsWithIdentifiers:names];

iOS10以下

1.創(chuàng)建通知

UILocalNotification *localNotification = [[UILocalNotification alloc]init];
    
    // 設置觸發(fā)時間
    localNotification.fireDate = date;
    // 設置時區(qū)  以當前手機運行的時區(qū)為準
    localNotification.timeZone = [NSTimeZone localTimeZone];
    // 設置推送 顯示的內容
    localNotification.alertTitle = @"title";
    localNotification.alertBody = @"body";
    // 設置 角標
    localNotification.applicationIconBadgeNumber = 1;
    // 不設置此屬性陪捷,則默認不重復
    localNotification.repeatInterval =  repeatInterval;
    
    // 設置推送的聲音
    localNotification.soundName =  UILocalNotificationDefaultSoundName;
    
    
    localNotification.userInfo = userInfo;
    //添加到通知
    [[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
    

2.重復提醒

重復提醒通過設置 repeatInterval 就可以

value effect
NSCalendarUnitDay 每天
NSCalendarUnitWeekday 每周
NSCalendarUnitMonth 每月
NSCalendarUnitYear 每年
... ...

等等...
同樣如果有需求是周一到周五某時提醒也用循環(huán)創(chuàng)建五個通知

for (NSInteger i = 2; i <= 6; i++) {
//同樣用NSDateComponents設置weekday來實現星期幾的提醒
//先用傳入的date創(chuàng)建時間容器回窘,然后修改weekday后再轉為NSDate
    NSDateComponents * components = [[NSCalendar currentCalendar] components:NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond fromDate:date];
    components.weekday = i;
    NSDate * newDate = [[NSCalendar currentCalendar] dateFromComponents:components];
//吧newDate再賦值給fireDate
}

3.取消通知

//獲取所有通知
NSArray * localNotifications = [[UIApplication sharedApplication] scheduledLocalNotifications];
    for (UILocalNotification * notification in localNotifications) {
        //找到和要刪除的通知同名的通知刪除
        if ([notification.userInfo[@"notificationName"] hasPrefix:notificationName]) {
            //刪除通知
            [[UIApplication sharedApplication] cancelLocalNotification:notification];

        }
    }
    

注冊通知

//注冊通知
[[UIApplication sharedApplication] registerForRemoteNotifications];
    

快捷使用

封裝了一個可以直接使用的類:ZBLocalNotification

//提醒重復類型
typedef NS_ENUM(NSInteger, ZBLocalNotificationRepeat) {
    ZBLocalNotificationRepeatNone,          //不重復
    ZBLocalNotificationRepeatEveryDay,      //每天
    ZBLocalNotificationRepeatEveryWeek,     //每周
    ZBLocalNotificationRepeatEveryMonth,    //每月
    ZBLocalNotificationRepeatEveryYear,     //每年
    ZBLocalNotificationRepeatEveryWorkDay   //每周一到周五(工作日)
};

//標識通知屬性的key
typedef NSString * ZBLocalNotificationKey;
//標識通知聲音文件名字的key
typedef NSString * ZBLocalNotificationSoundName;

extern ZBLocalNotificationKey const ZBNotificationFireDate;     //標識提醒時間
extern ZBLocalNotificationKey const ZBNotificationAlertTitle;   //標識標題
extern ZBLocalNotificationKey const ZBNotificationAlertBody;    //標識提醒內容
extern ZBLocalNotificationKey const ZBNotificationAlertAction;  //標識按鈕
extern ZBLocalNotificationKey const ZBNotificationSoundName;    //標識聲音
extern ZBLocalNotificationKey const ZBNotificationUserInfoName; //標識通知名字
extern ZBLocalNotificationKey const ZBNotificationPriority;     //標識通知優(yōu)先級
extern ZBLocalNotificationKey const ZBNotificationRepeat;       //標識通知重復
extern ZBLocalNotificationSoundName const ZBNotificationSoundAlarm; //標識聲音為提醒
extern ZBLocalNotificationSoundName const ZBNotificationSoundOther; //標識聲音為其他

@interface ZBLocalNotification : NSObject

/**
 創(chuàng)建本地通知

 @param attribute 通知的屬性
 */
+ (void)createLocalNotificationWithAttribute:(NSDictionary *)attribute;

/**
 取消通知

 @param notificationName 通知名字
 */
+ (void)cancelLocalNotificationWithName:(NSString *)notificationName;

#ifdef NSFoundationVersionNumber_iOS_9_x_Max

/**
 注冊通知
 */
+ (void)requestUNUserNotificationAuthorization;

#endif

@end

創(chuàng)建時間為date的每天重復提醒例子:
導入#import "ZBLocalNotification.h"

[ZBLocalNotification createLocalNotificationWithAttribute:
                                @{ZBNotificationUserInfoName:@"notificationName",
                                  ZBNotificationSoundName:ZBNotificationSoundAlarm,
                                  ZBNotificationAlertBody:@"提醒內容",
                                  ZBNotificationAlertTitle:@"提醒標題",
                                  ZBNotificationFireDate:date,
                                  ZBNotificationPriority:@(0),
                                  ZBNotificationRepeat:@(ZBLocalNotificationRepeatEveryDay)
                                  }];
                                  

取消名字為 “notificationName” 的通知:

[ZBLocalNotification cancelLocalNotificationWithName:@"notificationName"];

通知優(yōu)先級問題

如果設置了多個推送通知,并且時間都在同一個時刻時市袖,就是同時收到多個推送通知時啡直,想要只顯示優(yōu)先級最高的一個,我是在AppDelegate里這樣處理的(希望有更好的方法能不吝賜教 :) ):
先創(chuàng)建一個userInfo容器苍碟,保存同一時間收到的通知
self.userInfos = [[NSMutableArray alloc]init];

//處理接收到的通知信息
- (void)filteredUserInfo {
    if (self.userInfos.count == 0) {
        return;
    }
    //選出你希望顯示的通知信息酒觅,以下方法是顯示優(yōu)先級高的,你可以判斷不同的條件
    //排序所有收到的通知信息微峰,對比優(yōu)先級舷丹,把優(yōu)先級最高的放首位
    [self.userInfos sortUsingComparator:^NSComparisonResult(NSDictionary * obj1, NSDictionary * obj2) {
        if ([obj1[ZBNotificationPriority] integerValue] < [obj2[ZBNotificationPriority] integerValue]) {
            return NSOrderedDescending;
        }
        return NSOrderedSame;
    }];
    
    //自定義展示推送內容
    [self showAlarmAlertWithUserInfo:self.userInfos.firstObject];
    //重置userInfo容器
    [self.userInfos removeAllObjects];
}
//添加通知到userInfo容器
- (void)waitMultipleUserInfo:(NSDictionary *)userInfo {
    [self.userInfos addObject:userInfo];
    //創(chuàng)建信號量,設置為0
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    dispatch_queue_t quene = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    dispatch_async(quene, ^{
        
        if (self.userInfos.count == 1) {
            //信號量為0時蜓肆,那么這個函數就阻塞當前線程等待timeout颜凯,時間到后繼續(xù)執(zhí)行
            //0.3秒內第一次進入則等待0.3秒,0.3秒后對本時間段內提醒提取優(yōu)先級最高的一個
            //就是保存在極短時間內(我這里設置為0.3s)收到的所有通知仗扬,然后進行處理
            dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, 0.3 * NSEC_PER_SEC));
            dispatch_async(dispatch_get_main_queue(), ^{
                [self filteredUserInfo];
            });
        }
    });
    
}

#pragma mark - localNotification
// iOS10以下 在前臺收到推送回調
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification{
    [self waitMultipleUserInfo:notification.userInfo];
}

#ifdef NSFoundationVersionNumber_iOS_9_x_Max

#pragma mark - UNUserNotificationCenterDelegate
// iOS10 在前臺收到推送回調
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(nonnull UNNotification *)notification withCompletionHandler:(nonnull void (^)(UNNotificationPresentationOptions))completionHandler{
    UNNotificationRequest *request = notification.request; // 收到推送的請求
    UNNotificationContent *content = request.content; //收到推送消息的全部內容
    
    if ([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
        NSLog(@"iOS10 收到遠程通知");
    }else{
        NSLog(@"ios10 收到本地通知userInfo:%@",content.userInfo);
        [self waitMultipleUserInfo:content.userInfo];
    }
    completionHandler(UNNotificationPresentationOptionBadge |
                      UNNotificationPresentationOptionSound
                       );
    
}

#endif

代碼下載

ZBLocalNotification類下載地址:
iOS本地推送封裝(定時推送症概、重復提醒)
ZBLocalNotification類下載地址:
iOS本地推送封裝(定時推送、重復提醒)

疑問

比如需求是可以自定義重復的時間:

  • 每隔兩周的周二早上8點提醒
  • 每隔三個月的7號早上8點提醒

這種時候的怎么實現早芭,NSDateComponents需要怎么設置彼城?

謝謝!

歡迎討論,未完待續(xù)


最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市侮邀,隨后出現的幾起案子抹剩,更是在濱河造成了極大的恐慌,老刑警劉巖筐眷,帶你破解...
    沈念sama閱讀 222,627評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異习柠,居然都是意外死亡匀谣,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 95,180評論 3 399
  • 文/潘曉璐 我一進店門资溃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來武翎,“玉大人,你說我怎么就攤上這事溶锭”Χ瘢” “怎么了?”我有些...
    開封第一講書人閱讀 169,346評論 0 362
  • 文/不壞的土叔 我叫張陵趴捅,是天一觀的道長垫毙。 經常有香客問我,道長拱绑,這世上最難降的妖魔是什么综芥? 我笑而不...
    開封第一講書人閱讀 60,097評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮猎拨,結果婚禮上膀藐,老公的妹妹穿的比我還像新娘。我一直安慰自己红省,他們只是感情好额各,可當我...
    茶點故事閱讀 69,100評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著吧恃,像睡著了一般虾啦。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上痕寓,一...
    開封第一講書人閱讀 52,696評論 1 312
  • 那天缸逃,我揣著相機與錄音,去河邊找鬼厂抽。 笑死需频,一個胖子當著我的面吹牛,可吹牛的內容都是我干的筷凤。 我是一名探鬼主播昭殉,決...
    沈念sama閱讀 41,165評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼苞七,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了挪丢?” 一聲冷哼從身側響起蹂风,我...
    開封第一講書人閱讀 40,108評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎乾蓬,沒想到半個月后惠啄,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 46,646評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡任内,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,709評論 3 342
  • 正文 我和宋清朗相戀三年撵渡,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片死嗦。...
    茶點故事閱讀 40,861評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡趋距,死狀恐怖,靈堂內的尸體忽然破棺而出越除,到底是詐尸還是另有隱情节腐,我是刑警寧澤,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布摘盆,位于F島的核電站翼雀,受9級特大地震影響,放射性物質發(fā)生泄漏孩擂。R本人自食惡果不足惜狼渊,卻給世界環(huán)境...
    茶點故事閱讀 42,196評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望肋殴。 院中可真熱鬧,春花似錦坦弟、人聲如沸护锤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,698評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽烙懦。三九已至,卻和暖如春赤炒,著一層夾襖步出監(jiān)牢的瞬間氯析,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,804評論 1 274
  • 我被黑心中介騙來泰國打工莺褒, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留掩缓,地道東北人。 一個月前我還...
    沈念sama閱讀 49,287評論 3 379
  • 正文 我出身青樓遵岩,卻偏偏與公主長得像你辣,于是被迫代替她去往敵國和親巡通。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,860評論 2 361

推薦閱讀更多精彩內容