一、簡(jiǎn)介
分為本地推送和遠(yuǎn)程推送2種。可以在應(yīng)用沒打開甚至手機(jī)鎖屏情況下給用戶以提示。它們都需要注冊(cè),注冊(cè)后系統(tǒng)會(huì)彈出提示框(如下圖)提示用戶石否同意,如果同意則正常使用;如果用戶不同意則下次打開程序也不會(huì)彈出改提示框,需要用戶到設(shè)置里面設(shè)置。一共有三種提示類型:
UIUserNotificationTypeBadge:應(yīng)用圖標(biāo)右上角的信息提示
UIUserNotificationTypeSound:播放提示音
UIUserNotificationTypeAlert:提示框

二、本地推送
1.注冊(cè)與處理
代碼如下:
/// 一般在在啟動(dòng)時(shí)注冊(cè)通知,程序被殺死,點(diǎn)擊通知后調(diào)用此程序
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
- (void)registerAPN {
// 注冊(cè)通知
if (@available(iOS 10.0, *)) { // iOS10 以上
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
[center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert + UNAuthorizationOptionSound) completionHandler:^(BOOL granted, NSError * _Nullable error) {
}];
} else {// iOS8.0 以上
UIUserNotificationSettings *setting = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:setting];
}
}
return YES;
}
/// 程序沒有被殺死(處于前臺(tái)或后臺(tái)),點(diǎn)擊通知后會(huì)調(diào)用此程序
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
// 這里添加處理代碼
}
可以看到,處理代碼有兩個(gè)方法,一個(gè)是
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification;
另一個(gè)是- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;
如果程序沒有被殺死,即處于前臺(tái)或者后臺(tái),那么調(diào)用前者;如果程序被殺死,則調(diào)用后者。
- (void)applicationWillResignActive:(UIApplication *)application {
#pragma mark -->NSLog(@"\n ===> 程序掛起 !"); 比如:當(dāng)有電話進(jìn)來(lái)或者鎖屏,這時(shí)你的應(yīng)用程會(huì)掛起,在這時(shí),UIApplicationDelegate委托會(huì)收到通知,調(diào)用 applicationWillResignActive 方法,你可以重寫這個(gè)方法,做掛起前的工作,比如關(guān)閉網(wǎng)絡(luò),保存數(shù)據(jù)。
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
#pragma mark --> NSLog(@"\n ===> 程序進(jìn)入后臺(tái) !");
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
#pragma mark --> NSLog(@"\n ===> 程序進(jìn)入前臺(tái) !");
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:0];
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
#pragma mark --> NSLog(@"\n ===> 程序重新激活 !"); 應(yīng)用程序在啟動(dòng)時(shí),在調(diào)用了 applicationDidFinishLaunching 方法之后也會(huì)調(diào)用 applicationDidBecomeActive 方法,所以你要確保你的代碼能夠分清復(fù)原與啟動(dòng),避免出現(xiàn)邏輯上的bug。(大白話就是說(shuō):只要啟動(dòng)app就會(huì)走此方法)。
}
- (void)applicationWillTerminate:(UIApplication *)application {
#pragma mark --> 當(dāng)用戶按下按鈕,或者關(guān)機(jī),程序都會(huì)被終止。當(dāng)一個(gè)程序?qū)⒁=K止時(shí)會(huì)調(diào)用 applicationWillTerminate 方法。但是如果長(zhǎng)主按鈕強(qiáng)制退出,則不會(huì)調(diào)用該方法。這個(gè)方法該執(zhí)行剩下的清理工作,比如所有的連接都能正常關(guān)閉,并在程序退出前執(zhí)行任何其他的必要的工作.
}
2.發(fā)送通知
- (void)addLocalNotice {
if (@available(iOS 10.0, *)) {
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
// 標(biāo)題
content.title = @"測(cè)試標(biāo)題";
content.subtitle = @"測(cè)試通知副標(biāo)題";
// 內(nèi)容
content.body = @"測(cè)試通知的具體內(nèi)容";
// 聲音
// content.sound = [UNNotificationSound defaultSound];
content.sound = [UNNotificationSound soundNamed:@"Alert_ActivityGoalAttained_Salient_Haptic.caf"];
// 角標(biāo) (我這里測(cè)試的角標(biāo)無(wú)效,暫時(shí)沒找到原因)
content.badge = @1;
// 多少秒后發(fā)送,可以將固定的日期轉(zhuǎn)化為時(shí)間
NSTimeInterval time = [[NSDate dateWithTimeIntervalSinceNow:2] timeIntervalSinceNow];
// NSTimeInterval time = 10;
// repeats,是否重復(fù),如果重復(fù)的話時(shí)間必須大于60s,要不會(huì)報(bào)錯(cuò)
UNTimeIntervalNotificationTrigger *trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:time repeats:NO];
/*
//如果想重復(fù)可以使用這個(gè),按日期
// 周一早上 8:00 上班
NSDateComponents *components = [[NSDateComponents alloc] init];
// 注意,weekday默認(rèn)是從周日開始
components.weekday = 2;
components.hour = 8;
UNCalendarNotificationTrigger *calendarTrigger = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:components repeats:YES];
*/
// 添加通知的標(biāo)識(shí)符,可以用于移除,更新等操作
NSString *identifier = @"noticeId";
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:identifier content:content trigger:trigger];
[center addNotificationRequest:request withCompletionHandler:^(NSError *_Nullable error) {
NSLog(@"成功添加推送");
}];
}else {
UILocalNotification *notif = [[UILocalNotification alloc] init];
// 發(fā)出推送的日期
notif.fireDate = [NSDate dateWithTimeIntervalSinceNow:5];
// 推送的內(nèi)容
notif.alertBody = @"你已經(jīng)10秒沒出現(xiàn)了";
// 可以添加特定信息
notif.userInfo = @{@"noticeId":@"00001"};
// 角標(biāo)
notif.applicationIconBadgeNumber = 1;
// 提示音
notif.soundName = UILocalNotificationDefaultSoundName;
// 每周循環(huán)提醒
notif.repeatInterval = NSCalendarUnitWeekOfYear;
[[UIApplication sharedApplication] scheduleLocalNotification:notif];
}
}
3. 取消通知
// 取消所有本地通知
[application cancelAllLocalNotifications];
三、遠(yuǎn)程推送
與Android上我們自己實(shí)現(xiàn)的推送服務(wù)不一樣,Apple對(duì)設(shè)備的控制非常嚴(yán)格,消息推送的流程必須要經(jīng)過(guò)APNs(Apple Push Notification service).
一般情況下如果一個(gè)程序退到后臺(tái)就不能運(yùn)行代碼(Audio、VoIP等等可以在后臺(tái)運(yùn)行),或者程序退出后,那么它就和對(duì)應(yīng)應(yīng)用的后臺(tái)服務(wù)器斷開了鏈接,就收不到服務(wù)器發(fā)送的信息了,但是每臺(tái)設(shè)備只要聯(lián)網(wǎng)就會(huì)和蘋果的APNs服務(wù)器建立一個(gè)長(zhǎng)連接(persistent IP connection),這樣只要通過(guò)蘋果的APNs服務(wù)器,我們自己的服務(wù)器就可以間接的和設(shè)備保持連接了,示意圖如下:

使用步驟:
1 勾選Backgroud Modes -> Remote notifications,主要是iOS7之后,蘋果支持后臺(tái)運(yùn)行,如果這里打開后,當(dāng)接收到遠(yuǎn)程推送后,程序在后臺(tái)也可以做一些處理,如下圖所示:
2.遠(yuǎn)程推送機(jī)制

你的應(yīng)用服務(wù)端將消息發(fā)送到apple的APNS服務(wù)器,APNS服務(wù)器將消息推送到指定的Iphone,最后由Iphone負(fù)責(zé)將消息推送至你的APP。在此先不說(shuō)這個(gè)過(guò)程是如何實(shí)現(xiàn)的,僅僅看這個(gè)流程,你可能會(huì)覺得,在你們服務(wù)端和客戶端之間增加了一個(gè)apple的APNS,不是增加開發(fā)者的負(fù)擔(dān)么?其實(shí)結(jié)果恰恰相反,因?yàn)閍pple對(duì)推送的統(tǒng)一管理,使我們開發(fā)者的工作變得異常簡(jiǎn)單。
3.服務(wù)端如何連接到客戶端的
如果你是做android開發(fā)的,你一定非常了解長(zhǎng)鏈接與心跳包。事實(shí)上,大部分的android應(yīng)用的推送也確實(shí)是通過(guò)長(zhǎng)鏈接來(lái)實(shí)現(xiàn)的。因?yàn)閍ndroid系統(tǒng)的開放性,APP是很容易做到自啟動(dòng)和后臺(tái)長(zhǎng)鏈接的,而心跳驗(yàn)證,就是始終保證長(zhǎng)鏈接屬于接通狀態(tài),然后由服務(wù)端直接推送消息。如果IOS開發(fā)者也采用這種思路,就十分困難了,在IOS中想要保持一個(gè)APP服務(wù)始終不被系統(tǒng)殺死,我只能說(shuō)太難了。通過(guò)上面的流程圖,對(duì)比android的推送思路,我們很容易明白,IOS中其實(shí)也始終有一個(gè)長(zhǎng)鏈接,那就是系統(tǒng)本身,這個(gè)長(zhǎng)鏈接始終與APNS服務(wù)器相連,然后統(tǒng)一管理所有應(yīng)用程序的推送。
4.這是IOS推送機(jī)制的優(yōu)勢(shì)?
1、因?yàn)橥扑偷姆?wù)端是appleID的驗(yàn)證用戶,推送可靠性會(huì)高。
2、所有推送消息由APNS統(tǒng)一管理,效率高。
3、在客戶端只需系統(tǒng)維護(hù)一個(gè)長(zhǎng)鏈接,節(jié)省了用戶流量消耗和手機(jī)的性能消耗,并且提高了安全性,使得有惡意推送和流氓軟件的幾率降低。
準(zhǔn)備工作:參考大神博客http://www.rzrgm.cn/ludashi/p/4093454.html
浙公網(wǎng)安備 33010602011771號(hào)