文章結(jié)構(gòu):
<a id="1"></a>前言
這階段在學(xué)習(xí)有關(guān) iOS 10 消息推送的內(nèi)容,通過查閱資料并親身實踐,對消息推送有了一定的理解。因此寫這篇文章,希望對剛接觸 iOS 消息推送的開發(fā)者有幫助。
Apple 應(yīng)用的消息推送分為本地消息推送(Local Notification)和遠程消息推送(Remote Notification)。當(dāng)有新的消息時,可以通過本地或遠程推送告知用戶,即使 App 并未運行。
- 本地消息推送不需要聯(lián)網(wǎng),由系統(tǒng)統(tǒng)一管理 App 推送的消息,App 只需與系統(tǒng)交互即可。本地消息推送適用于 iOS、tvOS 和 watchOS。
- 遠程消息推送需要連接網(wǎng)絡(luò),通過 App 或者后臺服務(wù)器與 Apple Push Notification(APN) 通信,再由 APN 將消息推送到終端上。遠程消息推送除了支持 iOS、tvOS 和 watchOS,還支持 macOS。
本文將大體介紹消息推送的相關(guān)內(nèi)容,并實現(xiàn)基本的本地消息推送。想直接看如何實現(xiàn)本地消息推送,請看“本地消息推送實現(xiàn)”部分。
<a id="2"></a>iOS 消息推送的基礎(chǔ)知識
<a id="21"></a>推送方式
盡管消息推送方式分為本地和遠程,但是他們展現(xiàn)給用戶的方式是一樣的,因為它們默認(rèn)使用的是系統(tǒng)提供的外觀。主要的推送方式有:
- 通知、橫幅
- 應(yīng)用圖標(biāo)標(biāo)記
- 帶有聲音的通知、橫幅或標(biāo)記
<a id="22"></a>管理消息推送
App must be configured at launch time to support local and remote notification.
首先,我們需要在 applicationDidFinishLaunching:
之前聲明支持消息推送的方式。如果想在 App 運行后某個時間再進行聲明的話,在此之前要避免推送消息。因為在聲明支持消息推送之前,發(fā)送任何消息都是無效的。
當(dāng)配置了消息推送的方式后,需要請求授權(quán):requestAuthorizationWithOptions:completionHandler:
,第一次調(diào)用該方法時,系統(tǒng)會提示用戶 App 需要推送消息,等待用戶確認(rèn)。系統(tǒng)自動保存用戶的授權(quán)結(jié)果,當(dāng)以后調(diào)用該方法時,就不會在出現(xiàn)提示了。
獲得推送消息權(quán)限后,就需要考慮以下幾個問題:
一、設(shè)定 Category。當(dāng) App 推送的消息很多,需要進行分類時,就需要設(shè)定 Category。
let generalCategory = UNNotificationCategory(identifier: "GENERAL",actions: [],intentIdentifiers: [],options: .customDismissAction)
// Register the category.
let center = UNUserNotificationCenter.current()
center.setNotificationCategories([generalCategory])
設(shè)定消息的 Category 后,就可以添加自定義的行為(action),這樣用戶就可以在不打開 App 的情況下,對消息進行簡單的操作。如果不為消息分配 Category,那么消息就會以默認(rèn)的形式推送,不帶有任何附加的行為。
二、為 Category 添加自定義的行為。每個 Category 最多可以包含四個自定義的行為。
let generalCategory = UNNotificationCategory(identifier: "GENERAL",actions: [],intentIdentifiers: [],options: .customDismissAction)
// Create the custom actions for the TIMER_EXPIRED category.
let snoozeAction = UNNotificationAction(identifier: "SNOOZE_ACTION",title: "Snooze", options: UNNotificationActionOptions(rawValue: 0))
let stopAction = UNNotificationAction(identifier: "STOP_ACTION",title: "Stop",options: .foreground)
let expiredCategory = UNNotificationCategory(identifier: "TIMER_EXPIRED", actions: [snoozeAction, stopAction],intentIdentifiers: [], options: UNNotificationCategoryOptions(rawValue: 0))
// Register the notification categories.
let center = UNUserNotificationCenter.current()
center.setNotificationCategories([generalCategory, expiredCategory])
三、配置通知聲音。本地和遠程推送都可以自定義聲音。自定義聲音的音頻編碼形式可以是以下幾種:
- Linear PCM
- MA(IMA/ADPCM)
- uLaw
- aLaw
而音頻文件應(yīng)該為 .aiff
、.wav
或 .caf
文件。音頻時長必須小于 30s,否則系統(tǒng)會使用默認(rèn)的聲音。Mac 里自帶了 afconvert 音頻格式轉(zhuǎn)換工具。如在終端中輸入如下代碼,可以將 16-bit linear PCM 編碼的 Submarine.aiff
文件轉(zhuǎn)化為 IMA4 編碼的 .caf
文件:
afconvert /System/Library/Sounds/Submarine.aiff ~/Desktop/sub.caf -d ima4 -f caff -v
四、管理推送設(shè)置。由于用戶可以在設(shè)置里自由的打開或關(guān)閉 App 推送功能,在程序中,需要判斷推送功能是否可用:getNotificationSettingsWithCompletionHandler:
。
五、管理推送消息。我們可以給用戶推送消息,也可以管理已經(jīng)推送或?qū)⒁扑偷南ⅰ.?dāng)一條消息已經(jīng)不具備時效性,那么我們就應(yīng)該把它從通知欄中消除。使用:removeDeliveredNotificationsWithIdentifiers:
或 removePendingNotificationsWithIdentifiers:
。
<a id="3"></a>本地消息推送實現(xiàn)
下面的代碼是實現(xiàn)了一個負(fù)責(zé)推送消息的對象,它包含了請求推送和創(chuàng)建推送消息的方法。
import UIKit
import UserNotifications
internal class LocalNotificationManager: NSObject {
static let shared = LocalNotificationManager()
private let notificationCenter = UNUserNotificationCenter.current()
private override init(){
super.init()
}
//用于請求推送權(quán)限
internal func requestAuthorization(){
notificationCenter.requestAuthorization(options: [.alert, .sound]){ (granted, error) in
if(granted&&error == nil){
}else{
}
}
}
//用于創(chuàng)建推送消息(創(chuàng)建的消息將在調(diào)用函數(shù)后十秒發(fā)出)
internal func createNewNotification(){
let content = UNMutableNotificationContent()
content.title = NSString.localizedUserNotificationString(forKey: "Alarm", arguments: nil)
content.body = NSString.localizedUserNotificationString(forKey: "WakeUp", arguments: nil)
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 10, repeats: false)
let request = UNNotificationRequest(identifier: "MyNotification", content: content, trigger: trigger)
notificationCenter.add(request){(error) in
if let _ = error {
assertionFailure()
}
}
}
}
有了上面管理消息推送的對象,實現(xiàn)簡單的本地消息推送只需要以下兩步:
一、在 AppDelegate.swift 里的 application:willFinishLaunchingWithOptions:
調(diào)用 requestAuthorization
請求授權(quán):
func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
LocalNotificationManager.shared.requestAuthorization()
return true
}
二、在要推送消息的地方調(diào)用:
LocalNotificationManager.shared.createNewNotification()
這樣就能收到推送的消息。
當(dāng) App 在后臺運行時,消息會以橫幅的形式出現(xiàn)。
當(dāng) App 在前臺運行時,消息會直接傳遞給 App,默認(rèn)狀態(tài)下不出現(xiàn)橫幅。想在前臺運行時也出現(xiàn)橫幅,可以實現(xiàn) UNUserNotificationCenterDelegate 代理方法,在 completionHandler 里添加需要的推送形式:
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler(UNNotificationPresentationOptions.alert)
}
歡迎訪問我的Github:LinShiwei (Lin Shiwei) · GitHub
有任何疑問的話,歡迎在下方評論區(qū)討論。