iOS10 本地推送你玩過了嗎?

首先來看一下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)是這樣的亭病。


Paste_Image.png

簡單的說就是本地推送通過 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>


Paste_Image.png

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就行了


Paste_Image.png

3岛请、iOS10的本地推送在哪里接收
當然了,使用<code>UNNotificationContent</code>創(chuàng)建的本地通知警绩,也是可以通過<code>Appdelegate</code>類中的

func application(_ application: UIApplication, didReceive notification: UILocalNotification)

方法的崇败。
不過,最好是通過UNUserNotificationCenterDelegate的相關(guān)的代理方法進行讀取肩祥,以及相關(guān)的后續(xù)操作后室。

Paste_Image.png

我們創(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)的交互功能。如圖所示:
收到推送之后下拉推送即可展示。


Paste_Image.png

Paste_Image.png

上代碼:

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è)置的交互界面姚糊。


Paste_Image.png

這樣的通知在哪里接收贿衍,并且做相關(guān)的操作呢?一樣救恨,還是在<code>UNUserNotificationCenterDelegate</code>的代理中進行接收


Paste_Image.png

主要代碼

 // 獲取特殊的 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

Paste_Image.png

主要代碼

if let imageURL = Bundle.main.url(forResource: "二哈", withExtension: "jpg"),
                let attachment = try? UNNotificationAttachment(identifier: "imageAttachment", url: imageURL, options: nil)
            {
                content.attachments = [attachment]
            }

實現(xiàn)效果:
圖片的

Paste_Image.png

Paste_Image.png

音頻的,可以直接播放的


Paste_Image.png

視頻的孝冒,也是可以直接播放的,但是好像是沒有聲音的


Paste_Image.png

Paste_Image.png

本地推送的簡單的實現(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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末穴店,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子拿穴,更是在濱河造成了極大的恐慌泣洞,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件贞言,死亡現(xiàn)場離奇詭異斜棚,居然都是意外死亡阀蒂,警方通過查閱死者的電腦和手機该窗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蚤霞,“玉大人酗失,你說我怎么就攤上這事∶列澹” “怎么了规肴?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我拖刃,道長删壮,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任兑牡,我火速辦了婚禮央碟,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘均函。我一直安慰自己亿虽,他們只是感情好,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布苞也。 她就那樣靜靜地躺著洛勉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪如迟。 梳的紋絲不亂的頭發(fā)上收毫,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天,我揣著相機與錄音殷勘,去河邊找鬼牛哺。 笑死,一個胖子當著我的面吹牛劳吠,可吹牛的內(nèi)容都是我干的引润。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼痒玩,長吁一口氣:“原來是場噩夢啊……” “哼淳附!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蠢古,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤奴曙,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后草讶,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體洽糟,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年堕战,在試婚紗的時候發(fā)現(xiàn)自己被綠了坤溃。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡嘱丢,死狀恐怖薪介,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情越驻,我是刑警寧澤汁政,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布道偷,位于F島的核電站,受9級特大地震影響记劈,放射性物質(zhì)發(fā)生泄漏勺鸦。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一目木、第九天 我趴在偏房一處隱蔽的房頂上張望祝旷。 院中可真熱鬧,春花似錦嘶窄、人聲如沸怀跛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽吻谋。三九已至,卻和暖如春现横,著一層夾襖步出監(jiān)牢的瞬間漓拾,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工戒祠, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留骇两,地道東北人。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓姜盈,卻偏偏與公主長得像低千,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子馏颂,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

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