首先來看一下iOS10的推送的基本的實現(xiàn)碳褒,和之前的推送有啥差別迄汛。
權(quán)限申請
iOS8之前,遠程推送和本地推送是區(qū)分對待的骤视,用戶只要同意遠程推送的是否允許就行了鞍爱。iOS8對遠程推送和本地推送權(quán)限允許進行了統(tǒng)一,無論是遠程推送還是本地推送专酗,在用戶看來效果都是一樣的睹逃,都是打斷用戶的操作。因此iOS8都需要申請權(quán)限。iOS 10 里進一步消除了本地通知和推送通知的區(qū)別沉填。向用戶申請通知權(quán)限非常簡單:
首先看一下本地推送的相關(guān)的比較
下面是iOS10以下版本的本地推送
1疗隶、首先是權(quán)限問題
// 申請允許通知的權(quán)限
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
registerPush(application: application)
return true
}
// 注冊推送
func registerPush(application:UIApplication) {
let settings = UIUserNotificationSettings.init(types: [.alert, .sound, .badge], categories: nil)
application.registerUserNotificationSettings(settings)
}
2、注冊本地推送
ViewController中的操作翼闹,點擊按鈕斑鼻,壓入后臺,等待4秒就會收到本地的推送
// 測試按鈕的點擊事件
func clickBtn1(sender:UIButton) {
//發(fā)送本地推送
let notification = UILocalNotification()
var fireDate = Date()
fireDate = fireDate.addingTimeInterval(TimeInterval.init(4.0))
notification.fireDate = fireDate
notification.alertBody = "body"
notification.userInfo = ["name":"張三","age":"20"]
notification.timeZone = NSTimeZone.default
notification.soundName = UILocalNotificationDefaultSoundName;
//發(fā)送通知
UIApplication.shared.scheduleLocalNotification(notification)
UIApplication.shared.applicationIconBadgeNumber += 1;
}
3猎荠、接收到本地推送的后續(xù)處理
當然了坚弱,不處理的話,就是默認進入app中关摇。
// 接收到本地推送
func application(_ application: UIApplication, didReceive notification: UILocalNotification) {
print("notification.userInfo = \(notification) notification.alertBody = \(notification.alertBody) notification.userInfo = \(notification.userInfo)");
}
收到本地推送之后荒叶,點擊推送的條,進入app输虱,獲取推送的相關(guān)的內(nèi)容
notification.userInfo = <UIConcreteLocalNotification: 0x15e8a3d0>{fire date = 2016年11月28日 星期一 中國標準時間16:42:24, time zone = Asia/Shanghai (GMT+8) offset 28800, repeat interval = 0, repeat count = UILocalNotificationInfiniteRepeatCount, next fire date = (null), user info = {
age = 20;
name = "\U5f20\U4e09";
}} notification.alertBody = Optional("body") notification.userInfo = Optional([AnyHashable("age"): 20, AnyHashable("name"): 張三])
當然了些楣,以上代碼。iOS10系統(tǒng)的機器也是能夠收到得到的宪睹,上下兼容嘛愁茁。
我們看一下,之前的本地推送的實現(xiàn)是這樣的亭病。
簡單的說就是本地推送通過 App 本地定制鹅很,加入到系統(tǒng)的 Schedule 里,然后在指定的時間推送指定文字命贴。
下面是iOS10版本的本地推送
1道宅、首先是權(quán)限問題
和iOS10以下的推送不同食听,iOS10的推送胸蛛,是基于UserNotifications 框架實現(xiàn)的,所以在實現(xiàn)之前先導入 UserNotifications框架
import UserNotifications
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
registerPush(application: application)
return true
}
// 注冊推送
func registerPush(application:UIApplication) {
// 首先通過系統(tǒng)版本進行判斷樱报,進行不同的注冊
let version:NSString = UIDevice.current.systemVersion as NSString;
let versionFloat = version.floatValue
if versionFloat < 10{
let settings = UIUserNotificationSettings.init(types: [.alert, .sound, .badge], categories: nil)
application.registerUserNotificationSettings(settings)
}else{
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) {
granted, error in
if granted {
// 用戶允許進行通知
print("用戶允許進行通知了")
}else{
print("用戶不允許進行通知了")
}
}
// 向 APNs 請求 token:
UIApplication.shared.registerForRemoteNotifications()
} else {
// Fallback on earlier versions
}
}
}
2葬项、接下來是注冊相關(guān)的本地推送的操作,當然了也得導入頭文件
import UserNotifications
// 測試按鈕的點擊事件
func clickBtn2(sender:UIButton) {
if #available(iOS 10.0, *) {
// 1迹蛤、創(chuàng)建推送的內(nèi)容
let content = UNMutableNotificationContent()
content.title = "iOS 10 的推送標題"
content.body = "iOS 10 的推送主體"
content.subtitle = "iOS 10 的副標題"
content.userInfo = ["name":"張三","age":"20"]
// 2民珍、創(chuàng)建發(fā)送觸發(fā)
/* 觸發(fā)器分三種:
UNTimeIntervalNotificationTrigger : 在一定時間后觸發(fā),如果設(shè)置重復(fù)的話盗飒,timeInterval不能小于60
UNCalendarNotificationTrigger: 在某天某時觸發(fā)嚷量,可重復(fù)
UNLocationNotificationTrigger : 進入或離開某個地理區(qū)域時觸發(fā) */
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 2, repeats: false)
// 3. 發(fā)送請求標識符
let requestIdentifier = "firstLocationPush"
// 4、創(chuàng)建一個發(fā)送請求
let request = UNNotificationRequest(identifier: requestIdentifier, content: content, trigger: trigger)
// 5逆趣、將請求添加到發(fā)送中心
UNUserNotificationCenter.current().add(request, withCompletionHandler: { (error) in
if error == nil{
print("Time Interval Notification scheduled: \(requestIdentifier)")
}
})
} else {
// Fallback on earlier versions
}
}
UserNotifications 中對通知進行了統(tǒng)一蝶溶。我們通過通知的內(nèi)容 (<code>UNNotificationContent</code>),發(fā)送的時機(<code>UNNotificationTrigger</code>) 以及一個發(fā)送通知的 String類型的標識符,來生成一個 <code>UNNotificationRequest</code>類型的發(fā)送請求抖所。最后梨州,我們將這個請求添加到 <code>UNUserNotificationCenter.current()</code>中,就可以等待通知到達了田轧。
那么本地推送的實現(xiàn)就變成了這樣:
<a href="http://www.reibang.com/p/2f3202b5e758">圖片來自</a>
Local Notifications 通過定義 <code>Content</code> 和 <code>Trigger</code> 向<code> UNUserNotificationCenter</code> 進行 <code>request</code> 這三部曲來實現(xiàn)暴匠。
PS:補充一下
/* 觸發(fā)器分三種:
UNTimeIntervalNotificationTrigger : 在一定時間后觸發(fā),如果設(shè)置重復(fù)的話傻粘,timeInterval不能小于60
UNCalendarNotificationTrigger: 在某天某時觸發(fā)每窖,可重復(fù)
UNLocationNotificationTrigger : 進入或離開某個地理區(qū)域時觸發(fā) */
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 2, repeats: true)
這么寫崩潰了,原因是這個樣子滴抹腿。設(shè)置時間大于60S就行了
3岛请、iOS10的本地推送在哪里接收
當然了,使用<code>UNNotificationContent</code>創(chuàng)建的本地通知警绩,也是可以通過<code>Appdelegate</code>類中的
func application(_ application: UIApplication, didReceive notification: UILocalNotification)
方法的崇败。
不過,最好是通過UNUserNotificationCenterDelegate的相關(guān)的代理方法進行讀取肩祥,以及相關(guān)的后續(xù)操作后室。
我們創(chuàng)建一個新的類<code>NotificationHandler</code>,來遵守代理混狠,進行相關(guān)的操作
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
let notificationHandler = NotificationHandler()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
// 注冊推送
registerPush(application: application)
// 添加iOS10 推送的相關(guān)的代理
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().delegate = notificationHandler
} else {
// Fallback on earlier versions
}
return true
}
}
import UIKit
import UserNotifications
class NotificationHandler: NSObject,UNUserNotificationCenterDelegate {
@available(iOS 10.0, *)
// 點擊推送框的時候岸霹,就會走這個方法。不管是本地推送還是遠程推送将饺,相比之前更加方便了
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
}
@available(iOS 10.0, *)
// 展示之前進行的設(shè)置
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
}
}
首先熟悉下<code>func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void)</code>
獲取一個本地推送的相關(guān)的信息
@available(iOS 10.0, *)
// 點擊推送框的時候贡避,就會走這個方法。不管是本地推送還是遠程推送予弧,相比之前更加方便了
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
let userInfo = response.notification.request.content.userInfo
let title = response.notification.request.content.title
let subTitle = response.notification.request.content.subtitle
let categoryIdentifier = response.notification.request.content.categoryIdentifier
let body = response.notification.request.content.body
let content = response.notification.request.content
let identifier = response.notification.request.identifier
print(" userInfo = \(userInfo)\n title = \(title)\n subTitle = \(subTitle)\n categoryIdentifier = \(categoryIdentifier)\n body = \(body)\n identifier = \(identifier) \n content = \(content)\n ")
}
打印結(jié)果
userInfo = [AnyHashable("name"): 張三, AnyHashable("age"): 20]
title = iOS 10 的推送標題
subTitle = iOS 10 的副標題
categoryIdentifier = firstLocationPush
body = iOS 10 的推送主體
identifier = firstLocationPush
content = <UNNotificationContent: 0x1742e3800; title: iOS 10 的推送標題, subtitle: iOS 10 的副標題, body: iOS 10 的推送主體, categoryIdentifier: firstLocationPush, launchImageName: , peopleIdentifiers: (
), threadIdentifier: , attachments: (
), badge: (null), sound: (null), hasDefaultAction: YES, shouldAddToNotificationsList: YES, shouldAlwaysAlertWhileAppIsForeground: NO, shouldLockDevice: NO, shouldPauseMedia: NO, isSnoozeable: NO, fromSnooze: NO, darwinNotificationName: (null), darwinSnoozedNotificationName: (null)
了解下<code>func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void)</code>方法
當收到推送刮吧,不管是遠程的還是本地的,在展示推送之前都會先走這個方法掖蛤,可以打斷點測試杀捻。
@available(iOS 10.0, *)
// 展示之前進行的設(shè)置
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
let identifier = notification.request.identifier
if identifier == "firstLocationPush"{
completionHandler([.alert, .sound])
}else{
// 如果不想顯示某個通知,可以直接用空 options 調(diào)用 completionHandler:
completionHandler([])
}
}
之前的推送蚓庭,當app在前臺是不能顯示的致讥,iOS10就可以,怎么實現(xiàn)器赞?上面已經(jīng)實現(xiàn)了垢袱。在上面的方法中可以通過不同的標識來進行不同的設(shè)置,有的推送收到了可以在前臺顯示港柜,有的只能在后臺顯示请契。
iOS10的推送增加了相關(guān)的交互功能。如圖所示:
收到推送之后下拉推送即可展示。
上代碼:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
// 注冊推送
registerPush(application: application)
registerNotificationCategory()
// 添加iOS10 推送的相關(guān)的代理
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().delegate = notificationHandler
} else {
// Fallback on earlier versions
}
return true
}
// 設(shè)置特殊標識的通知條的交互
private func registerNotificationCategory() {
if #available(iOS 10.0, *) {
let saySomethingCategory: UNNotificationCategory = {
// 1
let inputAction = UNTextInputNotificationAction(
identifier: "input",
title: "Input",
options: [.foreground],
textInputButtonTitle: "Send",
textInputPlaceholder: "What do you want to say...")
// 2
let goodbyeAction = UNNotificationAction(
identifier: "goodbye",
title: "Goodbye",
options: [.foreground])
let cancelAction = UNNotificationAction(
identifier: "cancel",
title: "Cancel",
options: [.destructive])
// 3
return UNNotificationCategory(identifier:"saySomethingCategory", actions: [inputAction, goodbyeAction, cancelAction], intentIdentifiers: [], options: [.customDismissAction])
}()
UNUserNotificationCenter.current().setNotificationCategories([saySomethingCategory])
} else {
// Fallback on earlier versions
}
}
以上代碼可以理解為提前注冊一個特殊標識的<code>UNNotificationCategory</code>
等收到<code>categoryIdentifier = "設(shè)置的categoryIdentifier"</code>的時候就會展示相關(guān)設(shè)置的交互界面姚糊。
這樣的通知在哪里接收贿衍,并且做相關(guān)的操作呢?一樣救恨,還是在<code>UNUserNotificationCenterDelegate</code>的代理中進行接收
主要代碼
// 獲取特殊的 categoryIdentifier 的操作信息
if categoryIdentifier == "saySomethingCategory" {
let text: String
if let actionType = SaySomethingCategoryAction(rawValue: response.actionIdentifier) {
switch actionType {
case .input:
text = (response as! UNTextInputNotificationResponse).userText
case .goodbye:
text = "Goodbye"
case .none:
text = ""
}
}else{
text = ""
}
print("text ===== \(text)")
}
取消和更新
取消
先來看一下取消通知吧
取消已經(jīng)顯示過的通知
// 取消已經(jīng)顯示過的通知贸辈,指定相關(guān)的 Identifier
UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: [requestIdentifier])
取消所有已經(jīng)展示過的所有的通知
UNUserNotificationCenter.current().removeAllDeliveredNotifications()
在之前的推送中上面的這兩種功能還是挺常見的。
取消正在等待顯示的通知,也就是提交了未顯示的通知
UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: [requestIdentifier])
取消所有正在等待顯示的通知,也就是提交了未顯示的通知
UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
更新
當我們更新相關(guān)的通知肠槽,只要將還沒有展示的通知擎淤,再次添加到<code>UNUserNotificationCenter.current()</code>中就行,記得<code>identifier</code>要保持一致奧秸仙,不然創(chuàng)建出來的是一個新的通知嘴拢。
在通知條中展示多媒體的信息
這個可以說是iOS10通知的一大特色。
直接上代碼寂纪,其實幾句話就搞定了席吴,當然了,蘋果支持的文件類型和大小也是有相關(guān)限制的捞蛋,具體請參考:
https://developer.apple.com/reference/usernotifications/unnotificationattachment
主要代碼
if let imageURL = Bundle.main.url(forResource: "二哈", withExtension: "jpg"),
let attachment = try? UNNotificationAttachment(identifier: "imageAttachment", url: imageURL, options: nil)
{
content.attachments = [attachment]
}
實現(xiàn)效果:
圖片的
音頻的,可以直接播放的
視頻的孝冒,也是可以直接播放的,但是好像是沒有聲音的
本地推送的簡單的實現(xiàn)拟杉,就嘗試這么多庄涡。
最后,獻上參考Demo地址:https://github.com/RunOfTheSnail/PushDemo001
下一章<a href="http://www.reibang.com/p/5d83250fb5a1">iOS10 遠程推送你玩過了嗎搬设?</a>
參考資料:
http://www.cocoachina.com/ios/20160628/16833.html
https://onevcat.com/2016/08/notification/
http://www.cnblogs.com/lidongq/p/5968923.html
https://developer.apple.com/reference/usernotifications/unnotificationattachment
圖畫的不錯
http://www.reibang.com/p/2f3202b5e758
http://www.cocoachina.com/ios/20161021/17820.html