關于遠程推送的原理可以參考這篇博客:
http://blog.tingyun.com/web/article/detail/571
模擬遠程推送的工具:
https://github.com/stefanhafeneger/PushMeBaby
https://github.com/noodlewerk/NWPusher
ios8.0遠程推送負載內(nèi)容
內(nèi)容格式必要要知道的啊,服務端一般會要我們客戶端定義好格式給他們的。
每一條通知的消息都會組成一個JSON字典對象,其格式如下所示,示例中的key值為蘋果官方所用key。自定義字段的時候要避開這些key值。
{
"aps" : {
"alert" : { // string or dictionary
"title" : "string"
"body" : "string",
"title-loc-key" : "string or null"
"title-loc-args" : "array of strings or null"
"action-loc-key" : "string or null"
"loc-key" : "string"
"loc-args" : "array of strings"
"launch-image" : "string"
},
"badge" : number,
"sound" : "string"
"content-available" : number;
"category" : "string"
},
}
aps:推送消息必須有的key
alert:推送消息包含此key值,系統(tǒng)就會根據(jù)用戶的設置展示標準的推送信息
badge:在app圖標上顯示消息數(shù)量,缺少此key值,消息數(shù)量就不會改變,消除標記時把此key對應的value設置為0
sound:設置推送聲音的key值,系統(tǒng)默認提示聲音對應的value值為default
content-available:此key值設置為1,系統(tǒng)接收到推送消息時就會調(diào)用不同的回調(diào)方法,iOS7之后配置后臺模式
category:UIMutableUserNotificationCategory's identifier 可操作通知類型的key值
title:簡短描述此調(diào)推送消息的目的,適用系統(tǒng)iOS8.2之后版本
body:推送的內(nèi)容
title-loc-key:功能類似title,附加功能是國際化,適用系統(tǒng)iOS8.2之后版本
title-loc-args:配合title-loc-key字段使用,適用系統(tǒng)iOS8.2之后版本
action-loc-key:可操作通知類型key值,不詳細敘述
loc-key:參考title-loc-key
loc-args:參考title-loc-args
launch-image:點擊推送消息或者移動事件滑塊時,顯示的圖片。如果缺少此key值,會加載app默認的啟動圖片。
當然以上key值并不是每條推送消息都必帶的key值,應當根據(jù)需求來選擇所需要的key值,除了以上系統(tǒng)所提供的key值外,你還可以自定義自己的key值,來作為消息推送的負載,自定義key值與aps此key值并列。如下格式:
{
"aps" : {
"alert" : "Provider push messag.",
"badge" : 9,
"sound" : "toAlice.aiff"
},
"Id" : 1314, // 自定義key值
"type" : "customType" // 自定義key值
}
{
ios10.0
{
"aps" : {
"alert" : {
"title" : "iOS遠程消息,我是主標題!-title",
"subtitle" : "iOS遠程消息,我是主標題!-Subtitle",
"body" : "Dely,why am i so handsome -body"
},
"category" : "alert",
"badge" : "2"
}
}
<h1>一、ios8的遠程推送
// 遠程推送APNs必須使用真機調(diào)試,并且必須使用付費的開發(fā)者賬號配置好對應的bundle ID和真機推送證書
UIApplication.shared.registerForRemoteNotifications()
let acceptAction = UIMutableUserNotificationAction()
acceptAction.identifier = "acceptAction"
acceptAction.title = "接受"
acceptAction.activationMode = .foreground
acceptAction.isDestructive = true
//拒絕按鈕
let rejectAction = UIMutableUserNotificationAction()
rejectAction.identifier = "rejectAction"
rejectAction.title = "拒絕"
rejectAction.activationMode = .background
rejectAction.isAuthenticationRequired = true //需要解鎖才能處理
rejectAction.isDestructive = true
//輸入按鈕
let inputAction = UIMutableUserNotificationAction()
inputAction.behavior = .textInput
inputAction.title = "輸入"
inputAction.identifier = "textInput"
inputAction.isDestructive = false
inputAction.activationMode = .background
let categorys = UIMutableUserNotificationCategory()
categorys.identifier = "alert"
let actions = [acceptAction,rejectAction,inputAction]
categorys.setActions(actions, for: .default)
var set = Set<UIMutableUserNotificationCategory>()
set.insert(categorys)
let repeatSettings = UIUserNotificationSettings(types: [.alert,.badge,.sound], categories: set)
UIApplication.shared.registerUserNotificationSettings(repeatSettings)
//獲取DeviceToken成功
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
//Swift中獲取deviceToken
//http://stackoverflow.com/questions/9372815/how-can-i-convert-my-device-token-nsdata-into-an-nsstring
var token: String = ""
for i in 0..<deviceToken.count {
token += String(format: "%02.2hhx", deviceToken[i] as CVarArg)
}
print(token)
}
//獲取DeviceToken失敗
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
}
1.用戶點擊通知會調(diào)用的方法
//MARK: ios 8.0之后點擊橫幅會調(diào)用的方法
// ----------------------------------------------------------------------------
// 監(jiān)聽遠程推送通知點擊(優(yōu)先級較低),接收到通知,用戶點擊進入才會調(diào)用該方法
當接收到推送通知之后, 并且滿足一下條件
app 在前臺時 ,會調(diào)用該方法
app 從后臺進入到前臺 (App一開始在后臺, app 鎖屏),點擊通知會調(diào)用該方法
app 完全退出
如果app 完全退出, 這時候,如果用戶點擊通知, 打開APP , 不會調(diào)用這個方法
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
print(userInfo)
UIApplication.shared.applicationIconBadgeNumber = 10
completionHandler(.newData)
}
2.一接收到通知就會立即調(diào)用該方法
效果: 當用戶收到通知之后, 即使沒有點擊也會調(diào)用這個方法
條件:
1.需要勾選后臺模式 remote notification,在后臺
2.必須保證發(fā)送的推送通知格式, 包括 "content-available":"隨便傳"
3.執(zhí)行completionHandler 回調(diào)代碼塊
// ----------------------------------------------------------------------------
// 監(jiān)聽遠程推送通知點擊(優(yōu)先級較高),一接收到通知就會立即調(diào)用該方法
當接收到推送通知之后, 并且滿足一下條件
當我們實現(xiàn), 這個方法時, 上面一個方法不再執(zhí)行
計時APP 完全退出, 也會調(diào)用這個方法
completionHandler : 統(tǒng)計我們處理的時間, 耗電量, 刷新預覽圖片
{"aps" :
{
"alert" : "This is some fancy message.",
"badge":1,
"content-available":"隨便傳"
}
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler;
執(zhí)行completionHandler 作用
1> 系統(tǒng)會估量App消耗的電量,并根據(jù)傳遞的UIBackgroundFetchResult 參數(shù)記錄新數(shù)據(jù)是否可用
2> 調(diào)用完成的處理代碼時,應用的界面縮略圖會自動更新
如果想要接收到通知后,不要用戶點擊通知, 就執(zhí)行以下代碼, 那么必須有三個要求:
1> 必須勾選后臺模式Remote Notification ;
2> 告訴系統(tǒng)是否有新的內(nèi)容更新(執(zhí)行完成代碼塊)
3> 服務器發(fā)送通知的格式必須要有content-available字段("content-available":"隨便傳")
<h1>二、ios10的遠程推送
注冊通知:
UIApplication.shared.registerForRemoteNotifications()
let action1 = UNNotificationAction(identifier: "action1", title: "接受邀請", options: .authenticationRequired)
let action2 = UNNotificationAction(identifier: "action2", title: "查看邀請", options: .foreground)
let action3 = UNNotificationAction(identifier: "action3", title: "取消", options: .destructive)
let action4 = UNTextInputNotificationAction(identifier: "action4", title: "輸入", options: .foreground, textInputButtonTitle: "發(fā)送", textInputPlaceholder: "tell me loudly")
let category1 = UNNotificationCategory(identifier: "alert", actions: [action1,action2,action3,action4], intentIdentifiers: [], options: .customDismissAction)
var set = Set<UNNotificationCategory>()
set.insert(category1)
center.setNotificationCategories(set)
//MARK: ios10 收到通知(本地和遠端)
/*
蘋果把本地通知跟遠程通知合二為一。區(qū)分本地通知跟遠程通知的類是UNPushNotificationTrigger.h類中,UNPushNotificationTrigger的類型是新增加的,通過它,我們可以得到一些通知的觸發(fā)條件 ,解釋如下:
UNPushNotificationTrigger (遠程通知) 遠程推送的通知類型
UNTimeIntervalNotificationTrigger (本地通知) 一定時間之后,重復或者不重復推送通知。我們可以設置timeInterval(時間間隔)和repeats(是否重復)。
UNCalendarNotificationTrigger(本地通知) 一定日期之后,重復或者不重復推送通知 例如,你每天8點推送一個通知,只要dateComponents為8,如果你想每天8點都推送這個通知,只要repeats為YES就可以了。
UNLocationNotificationTrigger (本地通知)地理位置的一種通知,
當用戶進入或離開一個地理區(qū)域來通知。
現(xiàn)在先提出來,后面我會一一代碼演示出每種用法。還是回到兩個很吊的代理方法吧
*/
//MARK: App處于前臺接收通知時
/*
1.下面這個代理方法,只會是app處于前臺狀態(tài) 前臺狀態(tài) and 前臺狀態(tài)下才會走,后臺模式下是不會走這里的
*/
public func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Swift.Void) {
if notification.request.trigger is UNPushNotificationTrigger {
//遠程通知
print("ios10.0 遠程通知")
}else {
//本地通知
print("ios10.0 收到本地通知")
}
completionHandler([.badge,.sound,.alert])
/*
4.不管前臺后臺狀態(tài)下。推送消息的橫幅都可以展示出來!后臺狀態(tài)不用說,前臺時需要在前臺代理方法中設置 ,設置如下:
// 需要執(zhí)行這個方法,選擇是否提醒用戶,有Badge、Sound、Alert三種類型可以設置
*/
}
// The method will be called on the delegate when the user responded to the notification by opening the application, dismissing the notification or choosing a UNNotificationAction. The delegate must be set before the application returns from applicationDidFinishLaunching:.
//App通知的點擊事件
/*
2.下面這個代理方法,只會是用戶點擊消息才會觸發(fā),如果使用戶長按(3DTouch)、彈出Action頁面等并不會觸發(fā)。點擊Action的時候會觸發(fā)!
*/
public func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Swift.Void){
UIApplication.shared.applicationIconBadgeNumber = 10
if response.notification.request.trigger is UNPushNotificationTrigger {
if response.actionIdentifier == "action4" {
let userSayStr = (response as? UNTextInputNotificationResponse)?.userText
print("輸入:\(userSayStr)")
}else if response.actionIdentifier == "action3" {
print("取消")
}else if response.actionIdentifier == "action2"{
print("看看邀請")
}else if response.actionIdentifier == "action1" {
print("接受邀請")
}
}else {
print("ios10 本地通知")
}
completionHandler()
/*
3.點擊代理最后需要執(zhí)行:completionHandler(); // 系統(tǒng)要求執(zhí)行這個方法
不然會報:
2016-09-27 14:42:16.353978 UserNotificationsDemo[1765:800117] Warning: UNUserNotificationCenter delegate received call to -userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler: but the completion handler was never called.
*/
}
參考文章:
http://www.itdecent.cn/p/c623c2b5966a
http://www.itdecent.cn/p/4b947569a548
http://www.itdecent.cn/p/c58f8322a278
http://www.itdecent.cn/p/81c6bd16c7ac
https://onevcat.com/2016/08/notification/