Swift-本地通知和遠(yuǎn)程通知

指推送通知跟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ō)明
push1.png
push2.png
push3.png
實(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è)條件

  1. 設(shè)置Background Modes –> Remote Notifications
  2. 在代理方法中調(diào)用代碼塊completionHandler(UIBackgroundFetchResultNewData);
  3. App服務(wù)器發(fā)送數(shù)據(jù)時(shí)要增加一個(gè)”content-available”字段,值隨意寫(xiě)
    滿足以上三個(gè)條件藏研,當(dāng)接收到通知時(shí)立即會(huì)調(diào)用代理方法

備注:本文部分參考wxdtan的專欄雷潮文檔資料敬矩。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市蠢挡,隨后出現(xiàn)的幾起案子弧岳,更是在濱河造成了極大的恐慌,老刑警劉巖业踏,帶你破解...
    沈念sama閱讀 222,729評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件禽炬,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡勤家,警方通過(guò)查閱死者的電腦和手機(jī)腹尖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)伐脖,“玉大人热幔,你說(shuō)我怎么就攤上這事乐设。” “怎么了断凶?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,461評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵伤提,是天一觀的道長(zhǎng)巫俺。 經(jīng)常有香客問(wèn)我认烁,道長(zhǎng),這世上最難降的妖魔是什么介汹? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,135評(píng)論 1 300
  • 正文 為了忘掉前任却嗡,我火速辦了婚禮,結(jié)果婚禮上嘹承,老公的妹妹穿的比我還像新娘窗价。我一直安慰自己,他們只是感情好叹卷,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,130評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布撼港。 她就那樣靜靜地躺著,像睡著了一般骤竹。 火紅的嫁衣襯著肌膚如雪帝牡。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,736評(píng)論 1 312
  • 那天蒙揣,我揣著相機(jī)與錄音靶溜,去河邊找鬼。 笑死懒震,一個(gè)胖子當(dāng)著我的面吹牛罩息,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播个扰,決...
    沈念sama閱讀 41,179評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼瓷炮,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了递宅?” 一聲冷哼從身側(cè)響起崭别,我...
    開(kāi)封第一講書(shū)人閱讀 40,124評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎恐锣,沒(méi)想到半個(gè)月后茅主,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,657評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡土榴,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,723評(píng)論 3 342
  • 正文 我和宋清朗相戀三年诀姚,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片玷禽。...
    茶點(diǎn)故事閱讀 40,872評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡赫段,死狀恐怖呀打,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情糯笙,我是刑警寧澤贬丛,帶...
    沈念sama閱讀 36,533評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站给涕,受9級(jí)特大地震影響豺憔,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜够庙,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,213評(píng)論 3 336
  • 文/蒙蒙 一恭应、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧耘眨,春花似錦昼榛、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,700評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至偶宫,卻和暖如春非迹,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背读宙。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,819評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工彻秆, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人结闸。 一個(gè)月前我還...
    沈念sama閱讀 49,304評(píng)論 3 379
  • 正文 我出身青樓唇兑,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親桦锄。 傳聞我的和親對(duì)象是個(gè)殘疾皇子扎附,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,876評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容

  • 點(diǎn)擊查看原文 Web SDK 開(kāi)發(fā)手冊(cè) SDK 概述 網(wǎng)易云信 SDK 為 Web 應(yīng)用提供一個(gè)完善的 IM 系統(tǒng)...
    layjoy閱讀 13,787評(píng)論 0 15
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)结耀,斷路器留夜,智...
    卡卡羅2017閱讀 134,716評(píng)論 18 139
  • 推送通知和NSNotification是有區(qū)別的: NSNotification:是看不到的 推送通知:是可以看到...
    AA君主閱讀 2,336評(píng)論 0 7
  • 你要知道 我們都有這樣的時(shí)候 一席之間對(duì)全世界失去了興趣 最愛(ài)的音樂(lè)也變得燥耳 最愛(ài)的事情也懶得...
    羈安閱讀 183評(píng)論 1 4
  • “路途遙遠(yuǎn)碍粥,一路安好『谝悖” 在這場(chǎng)人生中有太多的選擇需要你嚼摩,不管你需不需要有時(shí)你不得不做出決定,看似我們有很多選擇,...
    維京vivian閱讀 289評(píng)論 0 1