iOS 本地通知那些事

這塊顯示卡有點冷發表於2016-01-12

從iOS8開始,本質上來說有兩種通知:

  1. 本地通知(local notifications):由開發者定義,App觸發。觸發的時間是被事先安排好的。

  2. 遠端通知(remote notifications):這種情況下,通知可以被分成兩個類別:(a)推送通知(The push notifications),被伺服器初始化,然後通過APNS,最終到達使用者裝置。(b)靜默通知(The silent notifications),其實也是推送通知,但是他們並沒有被展示給使用者,而是立即被App處理以發起某項任務,最後當一切都完成時,一個本地通知 被顯示以提示使用者。

除了以上的2種以外,iOS8引入了地點通知(location notifications)。它其實也是本地通知(local notifications),但是他們只會在使用者一個特定的地理或者iBeacon區域時,才會被觸發。雖然我們看不到什麼細節,地點通知 (location notifications)實現起來也很容易。

從iOS8開始,通知被加入了新的特性。簡單地說,從現在開始,當一個通知被展示時,開發者可以指定使用者可觸發的具體的動作(actions),而且甚至不用啟動App也可以處理這個通知。

關於本地通知

  1. Alert or Banner:通知可以用alert或者banner來顯示,這取決於使用者在設定中得選擇。

  2. Sound: 當一個通知被送達時,你可以‘告訴’iOS播放一段自定義或者系統預設的聲音。

  3. Badge: 當通知到達時,一個badge數字會在App的圖示上顯示。當一個通知到達時,badge數字必增加1,當通知被處理後badge數字減1。當badge數字不為0或者為0,iOS會顯示或者隱藏badge。

可以被安排的本地通知的數量並不是無限的,最多有64個本地通知可以被安排和展示。如果多餘這個數字,所有超過這個數字的通知都會被廢棄。儘管如此,無論通知是以什麼樣的形式被安排的,最早的那個會被最先展示。

規定通知型別

我們來建立一個叫setupNotificationSettings()方法。

func setupNotificationSettings() {
    //規定通知型別
    var notificationTypes:UIUserNotificationType = [.Alert,.Sound,.Badge]
 
}

UIUserNotificationType現在是一個結構體型別。它包含了通知的所有可能的型別。

建立通知動作

一個動作就是一個UIMutableUserNotificationAction類的物件。UIMutableUserNotificationActioniOS8新引入的類,有著許多有用的配置屬性:

  1. 標示符(identifier): 字串,標示了一個對於整個App唯一的字串。很明顯,你永遠不應該在同一個App中定義兩個同樣地標示符。通過此標示符,我們可以決定在使用者點選不同的通知時,呼叫哪個動作。

  2. 標題(title):用來在展示給使用者的動作按鈕上。可以是簡單地或者本地化的字串。為了讓使用者能馬上理解動作的含義,一定要仔細考慮這個標題的值,最好是1到2個字元。

  3. destructive: 布林值。當設定為true時,通知中相應地按鈕的背景色會變成紅色。這隻會在banner通知中出現。通常,當動作代表著刪除、移除或者其他關鍵的動作是都會被標記為destructive以獲得使用者的注意。

  4. authenticationRequired: 布林值。當設定為true時,使用者在點選動作之前必須確認自己的身份。當一個動作十分關鍵時這非常有用,因為為認證的操作有可能會破壞App的資料。

  5. ActivationMode: 決定App在通知動作點選後是應該被啟動還是不被啟動。

  6. behavior: iOS9 新特性 可以支援在使用者通知中輸入文字

  7. parameters: iOS9 新特性

接下來我們來建立幾種不同的動作:


        //1 點選後消失,不會做任何事情
        var justInformAction = UIMutableUserNotificationAction()
        justInformAction.identifier = "justInform" 
        justInformAction.title = "OK"
        justInformAction.destructive = false
        justInformAction.authenticationRequired = false
        justInformAction.activationMode = .Background

         //2 啟動應用
        var secAction = UIMutableUserNotificationAction()
        secAction.identifier = "secAction"
        secAction.title = "OK"
        secAction.activationMode = .Foreground
        secAction.destructive = false
        secAction.authenticationRequired = false

我們把上邊的兩個方法放在setupNotificationSettings中。

當一個通知的所有動作被配置好了之後,他們可以被包進一個類目(categories)裡。如果你的通知支援動作,那麼你就必須建立一個類目 (categories)。通常情況下一個類目(category)配對一個通知,假設一個App中得所有通知都支援動作,那麼這個App也會有和通知一 樣多的類目(categories)。

類目(category)就是一個 UIMutableUserNotificationCategory類的物件,這也是iOS8新引入的類。這個類只有一個屬性和一個方法。標示符屬性用 來表示一個唯一的類目(category),方法用來將多個動作包含進來。

我們來讓我們來了解一下這個方法 (setActions):

public func setActions(actions: [UIUserNotificationAction]?, forContext context: UIUserNotificationActionContext)

第一個引數指明瞭需要包含進來的動作。是一個包含所有動作的陣列,他們在陣列中的順序也代表著他們將會在一個通知中呼叫的先後順序。

第二個引數非常重要。context形參是一個列舉型別,描述了通知alert顯示時的上下文,有兩個值:

  1. Default : 在螢幕的中央展示一個完整的alert。(未鎖屏時)

  2. Minimal : 展示一個banner alert。

在預設上下文(default context)中,類目最多接受4個動作,會以預先定義好的順序依次在螢幕中央顯示。在minimal上下文中,最多可以在banner alert中設定2個動作。注意在第二個情況中,你必須選擇一個較為重要的動作以顯示到banner通知裡。接下來我們會將這兩種情況都用程式碼實現。

        var category = UIMutableUserNotificationCategory()
        category.identifier = "category1"
        category.setActions([justInformAction], forContext: .Default)
        category.setActions([secAction], forContext: .Minimal)

然後…這樣就行啦,為一個通知相關的動作建立一個類目就這樣完成了。

註冊通知設定

通過上面的3個部分,我們已經將本地通知的所有新功能已經實現了。現在我們需要將這些設定註冊到使用者設定中。為了完成這個目標,我們將會用到 UIUserNotificationSettings類(iOS8新引入),然後在下面的init方法中,我們會指定通知型別和類目 (category)。

convenience init(forTypes types: UIUserNotificationType, categories: Set<UIUserNotificationCategory>?)

第一個引數是我們為通知設定的型別,第二個方法是一個集合(NSSet),在這個集合中必須包含一個App所有通知支援的類目。在本例中,我們只有一個類目,但是我們還是需要使用集合來傳遞它。

        let newNotificationSettings = UIUserNotificationSettings(forTypes: notificationTypes, categories: [category])
        //最後,讓我們將它註冊一下吧!
        UIApplication.sharedApplication().registerUserNotificationSettings(newNotificationSettings)

第一次啟動App時上述程式碼就會執行,它會在使用者設定中建立一條我們的App記錄。

最後,在我展現一個完整的setupNotificationSettings(),還有一點需要注意。這個方法會在viewDidLoad方法中 被呼叫,這意味著每當App被啟動的時候它都會執行一次。很顯然一遍又一遍的設定同樣地值是在做無用功,這樣如果我們將上面的方法用一個guard判斷執行一下的話就好了。

 let notificationSettings = UIApplication.sharedApplication().currentUserNotificationSettings()
        guard notificationSettings?.types != .None else{
            return
        }

首先,我們通過UIApplication的類方法currentUserNotificationSettings()來獲取通知的型別。通過這 個方法返回的UIUserNotificationSettings類的物件,我們可以檢查它的types列舉屬性。請記住這個屬性為列舉型別。如果它的 值為None,那麼通知型別就還沒有被註冊,然後我們就執行上面的方法來註冊通知型別,否則什麼也不做。

完整程式碼:

func setupNotificationSetings(){
        
        let notificationSettings = UIApplication.sharedApplication().currentUserNotificationSettings()
        guard notificationSettings?.types != .None else{
            return
        }
        
        
        //規定通知型別
        let notificationTypes:UIUserNotificationType = [.Alert,.Sound,.Badge]
        //建立通知動作
        
        //1 點選後消失,不會做任何事情
        let justInformAction = UIMutableUserNotificationAction()
        justInformAction.identifier = "justInform" //識別符號
        justInformAction.title = "OK"
        justInformAction.destructive = false
        justInformAction.authenticationRequired = false
        justInformAction.activationMode = .Background
        
        //2 啟動應用
        let secAction = UIMutableUserNotificationAction()
        secAction.identifier = "secAction"
        secAction.title = "OK"
        secAction.activationMode = .Foreground
        secAction.destructive = false
        secAction.authenticationRequired = false
        
        let category = UIMutableUserNotificationCategory()
        category.identifier = "category1"
        category.setActions([justInformAction,secAction], forContext: .Default)
       
        
        let newNotificationSettings = UIUserNotificationSettings(forTypes: notificationTypes, categories: [category])
        
        UIApplication.sharedApplication().registerUserNotificationSettings(newNotificationSettings)
    }

安排本地通知

如果你在iOS之前的版本中使用過本地通知的話,你一定知道安排一個通知是很簡單地事情。在iOS8,安排一個通知並沒有什麼變化。事實上,所有的基本設定都是一模一樣的。唯一的新東西就是必須給一個通知設定一個類目,這樣通知就能知道當使用者點選的時候該啟動哪些動作了。

我們會定義一個新的方法來配置和安排一個本地通知。在我們實現這個方法之前,我們先看看一個本地通知中得重要屬性:

  1. fireDate:一個通知應當被顯示的日期和時間。NSDate物件。

  2. alertBody:通知的內容。應當儘量的簡潔明瞭,這樣使用者才能馬上理解它。

  3. alertAction:在預設情況下,點選一個banner通知會導致App啟動。在以alert形式顯示的通知中,會建立一個和這個動作對應 的按鈕。在此屬性中,你必須指定這個按鈕的標題。

  4. 。。。等等

現在放我們定義這個方法配置這個通知。不用說先讓我們建立一個UILocalNotification物件

  func scheduleLocalNotification(){
        let localNotification = UILocalNotification()
        localNotification.fireDate = NSDate()
        localNotification.alertBody = "Hellor World"
        localNotification.alertAction = "View"
        //我們必須指定使用者點選通知後對應的類目動作。回憶一下,我們前面已經定義了一個類目和類目標示符,我們在這裡就能使用到這個標示符了
        localNotification.category = "category1"
        //最後,我們需要使用UIApplication的scheduleLocalNotification(_:) 方法來真正的安排一個通知,不然這個通知永遠都不會“通知”到你啦。
        UIApplication.sharedApplication().scheduleLocalNotification(localNotification)
    }

處理通知動作

現在關於通知,我們只差最後一個部分了,那就是處理使用者點選通知相關按鈕時候的各種動作。和往常一樣,這裡有幾個主要的委託方法我們需要實現。

介紹幾個代理方法,通過他們你可以方便的開發你的App。

  func application(application: UIApplication, didRegisterUserNotificationSettings notificationSettings: UIUserNotificationSettings) {
        
    }

第一個代理方法是關於通知設定的。這個代理方法在程式啟動時被呼叫(不管是正常啟動還是通過一個本地通知),包含了所有App通知的設定選項。

通過上述的方法,你可以得到所有UIUserNotificationSettings支援的型別。當你需要檢查你的App所支援的通知和動作的型別時,這個方法非常有用。別忘了,使用者可以通過使用者設定來改變通知型別,所以我們不能保證,初始的通知型別一直都有效。

  1. 當你安排了一個通知之後,無論你的App是否在執行,這個通知都將被推送。通常情況下,開發者設定通知如何在App沒有執行或者被掛起的時候被推 送,所有的程式碼實現也聚焦在這兩個方面。但是,我們也應該處理當App在執行時通知如何被處理。感謝蘋果,iOS SDK讓這變得非常簡單,有一個代理方法正可以處理這種情況:

 func application(application: UIApplication, didReceiveLocalNotification notification: UILocalNotification) {
        
    }

當然在某些情況下在App執行時你並不需要處理通知。但是在另外一個情況下,上面的代理方法是處理通知動作的地方。

現在讓我們來看看當使用者點選了一個通知動作按鈕後將會呼叫的代理方法。更具我們給動作設定的標示符(identifier),我們決定那個動作被呼叫,然後App就會執行對應的程式碼了。

我們將根據identifier的值給每一種情況傳送一個 NSNotification,在ViewController類中,我們監視這些NSNotification,然後我們處理他們。

讓我們從新的代理方法開始:

func application(application: UIApplication, handleActionWithIdentifier identifier: String?, forLocalNotification notification: UILocalNotification, completionHandler: () -> Void) {
        if identifier == "secAction"{
         NSNotificationCenter.defaultCenter().postNotificationName("secaction", object: nil)
        }
        
        completionHandler()
    }

在上述幾種情況中我們根據動作的的標示符,傳送不同名稱的NSNotification物件。注意到,我們在方法的結束呼叫了 completionHandler()方法,根據規定我們必須呼叫它,這樣系統才能知道我們已經處理完了通知動作。在處理本地通知時,這個代理方法非常 重要,在這裡你通過使用者的點選執行相應地程式碼。

接下來,讓我們開啟ViewController.swift檔案。首先,讓我們監視我們之前傳送的NSNotification。在viewDidLoad中加入下面的程式碼:

  NSNotificationCenter.defaultCenter().addObserver(self, selector: "secAction", name: "secaction", object: nil)

secAction是我們自己要實現的方法。

 func secAction(){
        print("我是 notification 啟用的方法")
    }

到這裡我們的基本介紹就完了。

如何在 iOS 8 中使用 Swift 實現本地通知(上)

如何在 iOS 8 中使用 Swift 實現本地通知(下)

參考

做好了本地推送不是不是也要考慮一下遠端的推送。

推送筆記

相關文章