什么是推送通知?
首先明確:**此處的推送通知跟我們的”NSNotification”沒有半毛錢關(guān)系
可以理解為: 向用戶推送一條信息來通知用戶某件事情
作用: 可以在APP退到后臺(tái),或者關(guān)閉時(shí);繼續(xù)推送一條消息告訴用戶某件事情
推送通知的應(yīng)用場(chǎng)景?
- (1) 一些任務(wù)管理APP,會(huì)在任務(wù)時(shí)間即將到達(dá)時(shí),通知你做該任務(wù);
(2) 健身App定時(shí)提醒你應(yīng)該健身了;
(3) 買過電影票后,提前半小時(shí)告訴你,電影即將開場(chǎng);
(4) 當(dāng)你QQ或者微信收到消息時(shí),即使退到后臺(tái),或者關(guān)閉APP,也可以收到信息通知告訴我們;
(5) 電商APP,推送一條消息通知我們有新品上架等等
推送通知的分類
-
本地推送通知
“本地”可以理解為”不聯(lián)網(wǎng)”;即使沒有網(wǎng)絡(luò)情況下,也可以推送通知消息
應(yīng)用場(chǎng)景: 確定知道未來某個(gè)時(shí)間點(diǎn)應(yīng)該提醒用戶什么
通知發(fā)送方:開發(fā)人員負(fù)責(zé)在app內(nèi)部發(fā)送 -
遠(yuǎn)程推送通知
與“本地”相對(duì),表示,必須在聯(lián)網(wǎng)情況下才會(huì)向用戶推送通知消息
遠(yuǎn)程推送服務(wù)腮考,又稱為APNs(Apple Push Notification Services)應(yīng)用場(chǎng)景:
- 不確定未來某個(gè)時(shí)間點(diǎn)應(yīng)該提醒用戶什么,臨時(shí)性的
- 當(dāng)APP徹底退出時(shí)也想繼續(xù)讓用戶獲取一些最新消息
使用原則: 誰能確定通知時(shí)間和內(nèi)容, 誰就可以發(fā)送(開發(fā)人員在APP內(nèi)部通過代碼發(fā)送=本地通知; 服務(wù)器可以確定通知時(shí)間和內(nèi)容=遠(yuǎn)程通知)*
遠(yuǎn)程推送的呈現(xiàn)效果
本地推送通知
在iOS8.0之后 使用本地通知需要得到用戶的許可 在didFinishLaunchingWithOptions里面添加請(qǐng)求
if(系統(tǒng)版本 >= 8.0)
{
// 注冊(cè)接收通知的類型
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:nil];
[application registerUserNotificationSettings:settings];
// 注冊(cè)允許接收遠(yuǎn)程推送通知
[application registerForRemoteNotifications];
}
else
{
// 如果是iOS7.0堡赔,使用以下方法注冊(cè)
[application registerForRemoteNotificationTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound];
}
//swfit:
if #available(iOS 8.0, *)
{
// 注冊(cè)接收通知的類型
let type = UIUserNotificationType.alert.rawValue | UIUserNotificationType.badge.rawValue | UIUserNotificationType.sound.rawValue
let settings = UIUserNotificationSettings(types: UIUserNotificationType(rawValue: type), categories: nil)
UIApplication.shared.registerUserNotificationSettings(settings)
// 注冊(cè)允許接收遠(yuǎn)程推送通知
UIApplication.shared.registerForRemoteNotifications()
}
發(fā)送一個(gè)本地通知
@IBAction func puchNotionfication(_ sender: Any)
{
// 如果是ios8.0以前, 以下代碼, 可以直接發(fā)送一個(gè)本地通知,
// 但是, 如果是ios8.0以后, 你需要主動(dòng)的請(qǐng)求授權(quán), 才可以
// 通知顯示的條件
// 必須不能再前臺(tái)
//1.創(chuàng)建一個(gè)t本地通知
let localNoti = UILocalNotification()
//2. 設(shè)置通知內(nèi)容
localNoti.alertBody = "這是一個(gè)好日字"
//3. 設(shè)置發(fā)送通知的時(shí)間觸發(fā)時(shí)間
localNoti.fireDate = Date(timeIntervalSinceNow: 4)
//重復(fù)周期
// localNoti.repeatInterval = .weekday
//設(shè)置滑動(dòng)文字
localNoti.hasAction = true
localNoti.alertAction = "回復(fù)"
// 啟動(dòng)圖片(當(dāng)用戶點(diǎn)擊了本地通知, 啟動(dòng)我們APP 的時(shí)候, 帶的啟動(dòng)圖片)
// 如果是在ios9.0以前, 當(dāng)鎖屏界面, 出現(xiàn)一個(gè)通知, 用戶點(diǎn)擊了通知, 啟動(dòng)APP 的時(shí)候, 會(huì)自動(dòng)將我們?cè)O(shè)置的圖片, 當(dāng)做啟動(dòng)圖像 來顯示
// ios9.0, 這個(gè)屬性, 不太靈
// 如果這個(gè)圖片,找不到, 會(huì)使用系統(tǒng)默認(rèn)的啟動(dòng)圖片
localNoti.alertLaunchImage = "2"
// 設(shè)置通知彈框的標(biāo)題
// 標(biāo)題, 這對(duì)于, 通知中心的通知有效
if #available(iOS 8.2, *)
{
localNoti.alertTitle = "斗地主"
}
// 設(shè)置圖標(biāo)右上角的數(shù)字(0 代表不顯示)
localNoti.applicationIconBadgeNumber = 3
// userInfo 額外信息
localNoti.userInfo = ["name":"哥哥", "sex":"女"]
//應(yīng)用程序級(jí)別的操作 ,調(diào)度本地通知,完成之后琐驴,會(huì)在特定的fireDate發(fā)出通知
UIApplication.shared.scheduleLocalNotification(localNoti)
}
其他的屬性和方法
調(diào)度本地推送通知(調(diào)度完畢后岖常,推送通知會(huì)在特地時(shí)間fireDate發(fā)出)
[[UIApplication sharedApplication] scheduleLocalNotification:ln];
獲得被調(diào)度(定制)的所有本地推送通知
@property(nonatomic,copy) NSArray *scheduledLocalNotifications;
(已經(jīng)發(fā)出且過期的推送通知就算調(diào)度結(jié)束胁勺,會(huì)自動(dòng)從這個(gè)數(shù)組中移除)
取消調(diào)度本地推送通知
- (void)cancelLocalNotification:(UILocalNotification *)notification;
- (void)cancelAllLocalNotifications;
立即發(fā)出本地推送通知
- (void)presentLocalNotificationNow:(UILocalNotification *)notification;
每隔多久重復(fù)發(fā)一次推送通知
@property(nonatomic) NSCalendarUnit repeatInterval;
點(diǎn)擊推送通知打開app時(shí)顯示的啟動(dòng)圖片
@property(nonatomic,copy) NSString *alertLaunchImage;
附加的額外信息
@property(nonatomic,copy) NSDictionary *userInfo;
時(shí)區(qū)
@property(nonatomic,copy) NSTimeZone *timeZone;
(一般設(shè)置為[NSTimeZone defaultTimeZone] ,跟隨手機(jī)的時(shí)區(qū))
點(diǎn)擊本地通知
當(dāng)用戶點(diǎn)擊本地推送通知暑诸,會(huì)自動(dòng)打開app逗威,這里有2種情況
- app并沒有關(guān)閉峰搪,一直隱藏在后臺(tái)
讓app進(jìn)入前臺(tái),并會(huì)調(diào)用AppDelegate的下面方法(并非重新啟動(dòng)app)
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification;
- app已經(jīng)被關(guān)閉(進(jìn)程已死)
啟動(dòng)app凯旭,啟動(dòng)完畢會(huì)調(diào)用AppDelegate的下面方法
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;
launchOptions參數(shù)通過UIApplicationLaunchOptionsLocalNotificationKey取出本地推送通知對(duì)象
添加一些額外的操作
func registerAuthor()
{
// Override point for customization after application launch.
if #available(iOS 8.0, *)
{
// 注冊(cè)接收通知的類型
let type = UIUserNotificationType.alert.rawValue | UIUserNotificationType.badge.rawValue | UIUserNotificationType.sound.rawValue
//1.創(chuàng)建z一組操作行為
let category = UIMutableUserNotificationCategory()
//1.1設(shè)置組標(biāo)識(shí)
category.identifier = "select"
//1.2設(shè)置組里面的行為
let action1 = UIMutableUserNotificationAction()
action1.identifier = "queding"
action1.title = "確定"
// behavior todo
// 代表, 用戶如果點(diǎn)擊了這個(gè)動(dòng)作, 拉到底, 是在前臺(tái)運(yùn)行這個(gè)動(dòng)作, 還是在后臺(tái)
action1.activationMode = .foreground
// 必須要解鎖之后, 行為才會(huì)執(zhí)行(如果activationMode, 是前臺(tái)狀態(tài), 那這個(gè)屬性, 就會(huì)被忽略)
action1.isAuthenticationRequired = true
// 是否是破壞性行為(會(huì)使用一個(gè)紅色的標(biāo)識(shí), 來標(biāo)識(shí)這個(gè)按鈕)
action1.isDestructive = false
//1.1設(shè)置組標(biāo)識(shí)
category.identifier = "select"
//1.2設(shè)置組里面的行為
let action2 = UIMutableUserNotificationAction()
action2.identifier = "huifu"
action2.title = "回復(fù)"
// behavior todo
if #available(iOS 9.0, *)
{
action2.behavior = .textInput
action2.parameters = [UIUserNotificationTextInputActionButtonTitleKey: "確定"]
}
// 代表, 用戶如果點(diǎn)擊了這個(gè)動(dòng)作, 拉到底, 是在前臺(tái)運(yùn)行這個(gè)動(dòng)作, 還是在后臺(tái)
action2.activationMode = .background
// 必須要解鎖之后, 行為才會(huì)執(zhí)行(如果activationMode, 是前臺(tái)狀態(tài), 那這個(gè)屬性, 就會(huì)被忽略)
action2.isAuthenticationRequired = false
// 是否是破壞性行為(會(huì)使用一個(gè)紅色的標(biāo)識(shí), 來標(biāo)識(shí)這個(gè)按鈕)
action2.isDestructive = false
let actions = [action1, action2]
// 如果針對(duì)于彈框樣式的通知
// default 代表, 最多可以顯示4個(gè)按鈕
// minimal, 代表,最多可以顯示2個(gè)按鈕
category.setActions(actions, for: .default)
//附加操作行為組
let categorys : Set<UIUserNotificationCategory> = [category]
let settings = UIUserNotificationSettings(types: UIUserNotificationType(rawValue: type), categories: categorys)
UIApplication.shared.registerUserNotificationSettings(settings)
// 注冊(cè)允許接收遠(yuǎn)程推送通知
UIApplication.shared.registerForRemoteNotifications()
}
}
// completionHandler, 系統(tǒng)提供的回調(diào)代碼塊, 執(zhí)行這個(gè)代碼塊, 到時(shí)候, 系統(tǒng)會(huì)采集一些信息
func application(_ application: UIApplication, handleActionWithIdentifier identifier: String?, for notification: UILocalNotification, completionHandler: @escaping () -> Void)
{
print(identifier,notification)
print("old")
completionHandler()
}
// 9.0
// 如果實(shí)現(xiàn)了這個(gè)方法, 那么上面一個(gè)方法, 就不再執(zhí)行
func application(_ application: UIApplication, handleActionWithIdentifier identifier: String?, for notification: UILocalNotification, withResponseInfo responseInfo: [AnyHashable : Any], completionHandler: @escaping () -> Void) {
print("new")
print(identifier,responseInfo)
completionHandler()
}
遠(yuǎn)程推送
什么是遠(yuǎn)程推送通知
- 顧名思義概耻,就是從遠(yuǎn)程服務(wù)器推送給客戶端的通知(需要聯(lián)網(wǎng))
- 遠(yuǎn)程推送服務(wù),又稱為APNs(Apple Push Notification Services
為什么需要遠(yuǎn)程推送通知尽纽?
傳統(tǒng)獲取數(shù)據(jù)的局限性
只要用戶關(guān)閉了app启盛,就無法跟app的服務(wù)器溝通擂送,無法從服務(wù)器上獲得最新的數(shù)據(jù)內(nèi)容
不管用戶打開還是關(guān)閉app,只要聯(lián)網(wǎng)了湿诊,都能接收到服務(wù)器推送的遠(yuǎn)程通知
所有的蘋果設(shè)備矫膨,在聯(lián)網(wǎng)狀態(tài)下差凹,都會(huì)與蘋果的服務(wù)器建立長(zhǎng)連接
什么是長(zhǎng)連接
只要聯(lián)網(wǎng)了,就一直建立連接長(zhǎng)連接的作用
時(shí)間校準(zhǔn)
系統(tǒng)升級(jí)
查找我的iPhone
.. ...長(zhǎng)連接的好處
數(shù)據(jù)傳輸速度快
數(shù)據(jù)保持最新狀態(tài)
獲取deviceToken
蘋果需要用戶的UDID和bundleID
qq案例分析
app 發(fā)送設(shè)備的UDID和
應(yīng)用的Bundle Identifier
給APNs服務(wù)器經(jīng)蘋果加密生成一個(gè)
deviceToken 返還給當(dāng)前appapp發(fā)送當(dāng)前用戶的deviceToken
和用戶的標(biāo)志(比如id或者qq) 給qq服務(wù)器qq服務(wù)器將用戶的deviceToken存進(jìn)數(shù)據(jù)庫
當(dāng)有人發(fā)送消息 李四的手機(jī)(昵稱:李四 QQ:56789)
發(fā)給張三(QQ12345):吃飯沒?消息先到qq服務(wù)器侧馅,然后去數(shù)據(jù)庫查詢張三的deviceToken
qq服務(wù)器通知蘋果服務(wù)器
deviceTokoen:888
body:李四:吃飯沒?蘋果服務(wù)器通過deviceToken找到張三現(xiàn)在的設(shè)備
一.開發(fā)iOS程序的推送功能, iOS端需要做的事
1.請(qǐng)求蘋果獲得deviceToken
2.得到蘋果返回的deviceToken,發(fā)送deviceToken給公司的服務(wù)器
- 監(jiān)聽用戶對(duì)通知的點(diǎn)擊
二.調(diào)試iOS的遠(yuǎn)程推送功能, 必備條件:
1.真機(jī)
2.調(diào)試推送需要的證書文件
1> aps_development.cer : 某臺(tái)電腦就能調(diào)試某個(gè)app的推送服務(wù)
2> iphone5_qq.mobileprovision : 某臺(tái)電腦就能利用某臺(tái)設(shè)備調(diào)試某個(gè)程序
三.發(fā)布具有推送服務(wù)的app
1> aps_production.cer : 如果發(fā)布的程序中包含了推送服務(wù),就必須安裝這個(gè)證書
2> qq.mobileprovision : 某臺(tái)電腦就能發(fā)布某個(gè)程序
制作證書
注冊(cè)遠(yuǎn)程推送通知
客戶端如果想接收APNs的遠(yuǎn)程推送通知危尿,必須先注冊(cè)(得到用戶的授權(quán))
一般在App啟動(dòng)完畢后就馬上注冊(cè)
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// 注冊(cè)遠(yuǎn)程通知
UIRemoteNotificationType type = UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound;
[application registerForRemoteNotificationTypes:type];
return YES;
}
- 注冊(cè)成功后會(huì)調(diào)用AppDelegate的下面方法,得到設(shè)備的deviceToken
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
NSLog(@"%@", deviceToken);
}
點(diǎn)擊遠(yuǎn)程推送通知
當(dāng)用戶點(diǎn)擊遠(yuǎn)程推送通知馁痴,會(huì)自動(dòng)打開app谊娇,這里有2種情況
app并沒有關(guān)閉,一直隱藏在后臺(tái)
讓app進(jìn)入前臺(tái)罗晕,并會(huì)調(diào)用AppDelegate的下面方法(并非重新啟動(dòng)app)
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo;
app已經(jīng)被關(guān)閉(進(jìn)程已死)
啟動(dòng)app济欢,啟動(dòng)完畢會(huì)調(diào)用AppDelegate的下面方法
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;
launchOptions參數(shù)通過UIApplicationLaunchOptionsRemoteNotificationKey取出服務(wù)器返回的字典內(nèi)容