指推送通知跟NSNotification有區(qū)別:
1、NSNotification是系統(tǒng)內(nèi)部發(fā)出通知,一般用于內(nèi)部事件的監(jiān)聽(tīng)千元,或者狀態(tài)的改變等等苫昌,是不可見(jiàn)的
2颤绕、本地通知與遠(yuǎn)程通知是可見(jiàn)的幸海,主要用于告知用戶或者發(fā)送一些App的內(nèi)容更新,推送一些相關(guān)的消息奥务,讓用戶知道App內(nèi)部發(fā)生了什么事情物独。
通知的注意點(diǎn)
1、App在前臺(tái)運(yùn)行的時(shí)候氯葬,通知不會(huì)展示出來(lái)
2挡篓、點(diǎn)擊通知,默認(rèn)會(huì)自動(dòng)打開(kāi)推送通知的App
3帚称、不管App是否打開(kāi)官研,通知都可以如期發(fā)出
1. 什么是本地推送通知
不需要聯(lián)網(wǎng)就可以發(fā)出的通知
使用場(chǎng)景:
提醒用戶完成一些任務(wù),比如:定時(shí)提醒闯睹,生活備注戏羽,看電影等等
推送通知屬性:
// 枚舉值-發(fā)出通知的時(shí)間(有局限性)
@property(nonatomic) NSCalendarUnit repeatInterval;
// 自定義-發(fā)出通知的時(shí)間(可以自由設(shè)定時(shí)間)
@property(nonatomic,copy) NSCalendar *repeatCalendar;
// 區(qū)域-創(chuàng)建只需要?jiǎng)?chuàng)建一個(gè)中心點(diǎn)與半徑就可以了
@property(nonatomic,copy) CLRegion *region
// 進(jìn)入?yún)^(qū)域發(fā)出一個(gè)通知,設(shè)置yes,只會(huì)發(fā)出一個(gè)通知楼吃,設(shè)置NO就會(huì)每次進(jìn)入這個(gè)區(qū)域都發(fā)送
@property(nonatomic,assign) BOOL regionTriggersOnce NO
// 設(shè)置通知的內(nèi)容
@property(nonatomic,copy) NSString *alertBody;
// 決定alertAction是否生效
@property(nonatomic) BOOL hasAction;
// 設(shè)置滑塊的文字
@property(nonatomic,copy) NSString *alertAction;
// 設(shè)置點(diǎn)擊通知的啟動(dòng)圖片(一般設(shè)置App啟動(dòng)圖片后始花,這里可以隨便寫(xiě))
@property(nonatomic,copy) NSString *alertLaunchImage;
// 設(shè)置alertTitle,就是通知內(nèi)容上面的文字
@property(nonatomic,copy) NSString *alertTitle
// 設(shè)置彈出的聲音
@property(nonatomic,copy) NSString *soundName;
// 設(shè)置App的消息條數(shù)
@property(nonatomic) NSInteger applicationIconBadgeNumber;
// 設(shè)置通知一些額外數(shù)據(jù)
@property(nonatomic,copy) NSDictionary *userInfo;
如何發(fā)出本地通知:
//發(fā)出一個(gè)電池電量為100的本地通知
let alertBody = "電池電量通知"
let localNotify = UILocalNotification()
localNotify.alertBody = alertBody
localNotify.soundName = UILocalNotificationDefaultSoundName
localNotify.userInfo = ["battery": 100]
UIApplication.shared.presentLocalNotificationNow(localNotify)
使用注意:
iOS7孩锡,不需要用戶授權(quán)就可發(fā)出通知酷宵,而iOS8以后,必須用戶授權(quán)才可以發(fā)出通知
//申請(qǐng)授權(quán)
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
guard #available(iOS 10, *) else {
// 請(qǐng)求授權(quán)
let typeValue = UIUserNotificationType.alert.rawValue |
UIUserNotificationType.badge.rawValue |
UIUserNotificationType.sound.rawValue
let type = UIUserNotificationType(rawValue: typeValue)
let setting = UIUserNotificationSettings(types: type, categories: nil)
UIApplication.shared.registerUserNotificationSettings(setting)
// 發(fā)送請(qǐng)求
UIApplication.shared.registerForRemoteNotifications()
return
}
let typeValue = UNAuthorizationOptions.alert.rawValue |
UNAuthorizationOptions.badge.rawValue |
UNAuthorizationOptions.sound.rawValue
UNUserNotificationCenter.current().requestAuthorization(options: UNAuthorizationOptions(rawValue: typeValue)) { (granted, error) in
if granted { // 同意
UIApplication.shared.registerForRemoteNotifications()
} else { // 拒絕
/// 彈出提示框
}
}
}
監(jiān)聽(tīng)通知躬窜,如果用戶打開(kāi)通知浇垦,可以讓用戶進(jìn)入一些特定的界面
func application(_ application: UIApplication, didReceive notification: UILocalNotification) {
NSLog(notification)
guard let userInfo = notification.userInfo else {
return
}
//處理通知
}
2. 什么是遠(yuǎn)程推送通知
<1>從遠(yuǎn)程服務(wù)器推送給客戶端的通知,需要連接網(wǎng)絡(luò)
<2>遠(yuǎn)程推送服務(wù)荣挨,又稱為APNs 蘋果推送通知服務(wù)(Apple Push Notification services)
<3>模擬器無(wú)法調(diào)試遠(yuǎn)程推送
傳統(tǒng)推送通知
傳統(tǒng)推送通知是相對(duì)于APNs而言的溜族,傳統(tǒng)推送通知的原理是:當(dāng)APP打開(kāi)時(shí)和App的服務(wù)器建立一個(gè)長(zhǎng)連接(需要網(wǎng)絡(luò)),當(dāng)需要通知的時(shí)候垦沉,App服務(wù)器通過(guò)長(zhǎng)連接向?qū)?yīng)的客戶端發(fā)送數(shù)據(jù)煌抒,當(dāng)客戶端接收到數(shù)據(jù)時(shí)使用UILocalNotfication本地通知的方式來(lái)展示,這樣就實(shí)現(xiàn)了傳統(tǒng)推送通知厕倍。
傳統(tǒng)推送通知必須要聯(lián)網(wǎng)寡壮,如果關(guān)閉了App或者打開(kāi)了App但是無(wú)法連接服務(wù)器了,這些情況都收不到通知了讹弯。
APNs
所有蘋果設(shè)備在聯(lián)網(wǎng)狀態(tài)下都會(huì)與蘋果服務(wù)器建立長(zhǎng)連接况既,連接是雙向的,蘋果設(shè)備可以向蘋果服務(wù)器發(fā)送請(qǐng)求组民,蘋果服務(wù)器也可以向蘋果設(shè)備發(fā)送請(qǐng)求棒仍。
蘋果服務(wù)器常用的通知功能:
<1>時(shí)間校準(zhǔn)
<2>系統(tǒng)升級(jí)
<3>查找我的iPhone
長(zhǎng)連接的好處:更加及時(shí)
為什么需要遠(yuǎn)程推送通知:
解決獲取傳統(tǒng)數(shù)據(jù)的局限性,讓數(shù)據(jù)實(shí)時(shí)更新
使用場(chǎng)景:
聊天功能(一般非即時(shí)聊天)臭胜、推送一下App的內(nèi)部新功能莫其、版本下載等
注:所有的蘋果設(shè)備癞尚,在聯(lián)網(wǎng)狀態(tài)下,都會(huì)與蘋果的服務(wù)器建立-長(zhǎng)連接
遠(yuǎn)程通知的過(guò)程:
例如微信App:首先每個(gè)聯(lián)網(wǎng)并打開(kāi)微信的App都與微信服務(wù)器有一個(gè)長(zhǎng)連接乱陡,當(dāng)微信A用戶向微信B用戶發(fā)送一個(gè)消息時(shí)浇揩,微信A用戶將消息發(fā)送到微信服務(wù)器,然后微信服務(wù)器判斷微信B用戶是否和微信服務(wù)器建立了長(zhǎng)連接憨颠,如果有直接通過(guò)微信B用戶和微信服務(wù)器建立的連接管道直接發(fā)送即可胳徽,這樣微信B用戶就能收到消息;如果微信B用戶此時(shí)沒(méi)有打開(kāi)微信App爽彤,那么微信服務(wù)器就將消息發(fā)送給蘋果服務(wù)器养盗,蘋果服務(wù)器再講消息發(fā)送到某臺(tái)蘋果設(shè)備上。蘋果是怎么知道該發(fā)送給那臺(tái)設(shè)備呢适篙?用戶A發(fā)送消息時(shí)需要將用戶B的UDID和微信App的Bundle ID 附帶在消息上一塊發(fā)送給B用戶爪瓜,這些消息微信服務(wù)器又發(fā)送給蘋果服務(wù)器,蘋果服務(wù)器通過(guò)UDID就知道發(fā)送給那臺(tái)設(shè)備了匙瘪,然后通過(guò)Bundle ID就知道是哪個(gè)App發(fā)送的了铆铆。蘋果根據(jù)UDID + Bundle ID 生成一個(gè)deviceToken, 這樣每條微信消息中都加上deviceToken蘋果服務(wù)器就能識(shí)別設(shè)備和App了。
圖形說(shuō)明
實(shí)現(xiàn)步驟:
1. 創(chuàng)建真機(jī)調(diào)試證書(shū)并配置推送證書(shū)文件:apns_development.cer和描述文件
首先創(chuàng)建真機(jī)證書(shū)丹喻、AppIDs(要選擇Push Notifications), AppIDs創(chuàng)建完后可以看到狀態(tài)是Configurable,是黃色的圓點(diǎn)薄货,此時(shí)還不能使用推送通知,還要繼續(xù)配置一下碍论,選擇Edit–>Push Notifications—> Create Certificate(創(chuàng)建推送通知證書(shū)),當(dāng)證書(shū)創(chuàng)建完成后谅猾,可以看到AppID中的狀態(tài)就變成了綠色的圓點(diǎn)(可用狀態(tài))
2. 請(qǐng)求蘋果服務(wù)器獲取deviceToken
import UserNotifications
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
guard #available(iOS 10, *) else {
// 請(qǐng)求授權(quán)
let typeValue = UIUserNotificationType.alert.rawValue |
UIUserNotificationType.badge.rawValue |
UIUserNotificationType.sound.rawValue
let type = UIUserNotificationType(rawValue: typeValue)
let setting = UIUserNotificationSettings(types: type, categories: nil)
UIApplication.shared.registerUserNotificationSettings(setting)
// 發(fā)送請(qǐng)求
UIApplication.shared.registerForRemoteNotifications()
return
}
let typeValue = UNAuthorizationOptions.alert.rawValue |
UNAuthorizationOptions.badge.rawValue |
UNAuthorizationOptions.sound.rawValue
UNUserNotificationCenter.current().requestAuthorization(options: UNAuthorizationOptions(rawValue: typeValue)) { (granted, error) in
if granted { // 同意
UIApplication.shared.registerForRemoteNotifications()
} else { // 拒絕
/// 彈出提示框
}
}
}
/// 當(dāng)請(qǐng)求到DeviceToken時(shí)調(diào)用
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
NSLog(deviceToken)
}
3. 發(fā)送deviceToken給App的服務(wù)器
//這里使用第三方阿里云推送SDK,所以在didRegisterForRemoteNotificationsWithDeviceToken中將deviceToken發(fā)送出去
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
NSLog(deviceToken)
CloudPushSDK.registerDevice(deviceToken) { (result) in
if result!.success {
NSLog("Register deviceToken success.")
} else {
NSLog("Register deviceToken failed, error:\(result!.error!)")
}
}
}
4.監(jiān)聽(tīng)用戶點(diǎn)擊遠(yuǎn)程推送通知的行為
//鎖屏和從后臺(tái)進(jìn)入前臺(tái)會(huì)調(diào)用該方法
func application(_ application: UIApplication, didReceive notification: UILocalNotification) {
NSLog(notification)
}
//在前臺(tái)調(diào)用下面該方法,該方法需要設(shè)置Background Modes --> Remote Notifications
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
let status = application.applicationState
switch status {
case .active:
NSLog("在前臺(tái)收到推送")
break
case .inactive:
NSLog("后臺(tái)->前臺(tái)")
break
case .background:
NSLog("后臺(tái)")
break
}
completionHandler(.newData)
}
上面那個(gè)代理方法都是用戶點(diǎn)擊通知以后才會(huì)調(diào)用鳍悠,如果想一收到消息(用戶還沒(méi)點(diǎn)擊通知)就會(huì)調(diào)用該方法税娜,需要有3個(gè)條件
- 設(shè)置Background Modes –> Remote Notifications
- 在代理方法中調(diào)用代碼塊completionHandler(UIBackgroundFetchResultNewData);
- App服務(wù)器發(fā)送數(shù)據(jù)時(shí)要增加一個(gè)”content-available”字段,值隨意寫(xiě)
滿足以上三個(gè)條件藏研,當(dāng)接收到通知時(shí)立即會(huì)調(diào)用代理方法