通知相關(guān)系列文章
iOS10 之前通知使用介紹
[iOS] 通知詳解: UIUserNotification
iOS10 相關(guān)API
[iOS] 通知詳解:iOS 10 UserNotifications API
iOS10 本地/遠程通知
[iOS] 通知詳解: iOS 10 UserNotifications
iOS10 通知附加包
[iOS] 通知詳解: iOS 10 UserNotifications -- 附加包Media Attachments
iOS10 自定義UI
[iOS] 通知詳解: iOS 10 UserNotifications -- 自定義通知UI
無論是遠程通知還是本地通知抹蚀,都可以添加附加包,自己根據(jù)文件URL來創(chuàng)建UNNotificationAttachment實例扰路,然后添加到相應(yīng)的通知請求的UNMutableNotificationContent實例中帖渠。區(qū)別是獲取附件的方式谒亦,一般本地通知的附件是放在本地的Bundle中的,只需要在創(chuàng)建本地通知的時候空郊,根據(jù)附件的URL創(chuàng)建相應(yīng)的UNNotificationAttachment即可份招;遠程通知,需要根據(jù)遠程的通知攜帶的URL地址狞甚,去初始化UNNotificationAttachment锁摔,接著就會通過Service Extensions服務(wù)來下載這些附件數(shù)據(jù),在通知中進行顯示哼审。
本地通知添加附加包
上面說了谐腰,本地通知的附加包數(shù)據(jù)是放在本地的,直接根據(jù)其文件的URL地址創(chuàng)建即可涩盾,下面給出一個示例:
// 創(chuàng)建通知內(nèi)容
let content = UNMutableNotificationContent()
content.title = "ios 10 local push test"
content.subtitle = "local push subtitle"
content.body = "這是一個iOS 10 之后的本地通知測試文本怔蚌,這里顯示的是消息的詳細內(nèi)容,另外這是一個添加的附件圖片的通知"
content.sound = .default
content.userInfo = ["info": "這里的信息是傳遞給app的payload內(nèi)容"]
// 加載本地的一張圖片作為附件
if let url = Bundle.main.url(forResource: "111", withExtension: "png") {
if let attch = try? UNNotificationAttachment(identifier: "identifierAttachment", url: url, options: nil) {
content.attachments = [attch]
}
}
// 創(chuàng)建觸發(fā)方式旁赊,10s后觸發(fā)
let timer = UNTimeIntervalNotificationTrigger(timeInterval: 10, repeats: false)
// 創(chuàng)建通知請求
let req = UNNotificationRequest(identifier: "reqid", content: content, trigger: timer)
// 添加請求到通知中心
UNUserNotificationCenter.current().add(req) { (error) in
print(error)
print("prepare for local push")
}
通知執(zhí)行后,在鎖屏狀態(tài)通知中心顯示為:
彈框的顯示效果
彈框下拉后會顯示一個大圖
也可以加載一段音樂椅野,例如加載一首歌终畅,只需要把上面的加載附件的部分代碼修改為:
// 加載本地的一張圖片作為附件
if let url = Bundle.main.url(forResource: "music", withExtension: "mp3") {
if let attch = try? UNNotificationAttachment(identifier: "identifierAttachment", url: url, options: nil) {
content.attachments = [attch]
}
}
彈框下拉后如下圖效果:
可以看到,這里可以直接播放竟闪,視頻的加載方式類似离福,只要不超過大小限制即可!
遠程通知攜帶附加包
遠程通知的附件數(shù)據(jù)是存放在服務(wù)端的炼蛤,所以我們發(fā)送的Payload需要添加mutable-content字段妖爷,并設(shè)置其值為1 ,告訴系統(tǒng)此通知是可變的理朋,然后再通過Service Extensions服務(wù)來下載對應(yīng)的數(shù)據(jù)創(chuàng)建attachments絮识,添加到相應(yīng)的通知里面,顯示在通知里嗽上。
Payload 模板:
{
"aps":
{
"alert":
{
"title":"iOS10遠程推送標(biāo)題",
"subtitle" : "iOS10 遠程推送副標(biāo)題",
"body":"這是在iOS10以上版本的推送內(nèi)容次舌,并且攜帶來一個圖片附件"
},
"badge":1,
"mutable-content":1,
"sound":"default",
"image":"http://pic29.nipic.com/20130511/9252150_174018365301_2.jpg"
}
}
添加 Service Extension 服務(wù)
首先,添加一個擴展服務(wù)Target
選擇:導(dǎo)航欄 File -> New -> Target
在彈出的頁面中選擇Notification Service Extension兽愤,下一步彼念,起一個名稱挪圾,完成即可!可以看到逐沙,項目中多了一個Target哲思,以及幾個相關(guān)的文件:
我需要在生成的NotificationService文件里處理我們發(fā)送的通知,添加相應(yīng)的附件吩案,可以看到NotificationService是繼承自UNNotificationContentExtension的棚赔,并重寫了他的兩個方法,定義了兩個屬性:
import UserNotifications
class NotificationService: UNNotificationServiceExtension {
var contentHandler: ((UNNotificationContent) -> Void)?
var bestAttemptContent: UNMutableNotificationContent?
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
self.contentHandler = contentHandler
bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
if let bestAttemptContent = bestAttemptContent {
// Modify the notification content here...
bestAttemptContent.title = "\(bestAttemptContent.title) [modified]"
contentHandler(bestAttemptContent)
}
}
override func serviceExtensionTimeWillExpire() {
// Called just before the extension will be terminated by the system.
// Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
contentHandler(bestAttemptContent)
}
}
如果我們什么都不更改务热,使用上面的Payload模版發(fā)送一個遠程通知試試忆嗜,會發(fā)現(xiàn)我們設(shè)置的標(biāo)題后面多了個[modified],這是因為修改了標(biāo)題崎岂±粒可見,通知調(diào)用了這個方法冲甘,但是绩卤,當(dāng)我們在這個文件內(nèi)添加打印log的print,或者斷點江醇,log信息并沒有輸出濒憋,斷點也沒有停,雖然這個方法確實是被系統(tǒng)調(diào)用了陶夜,這給我們的調(diào)試帶來了一些不方便凛驮。
我們主要是在didReceive方法里添加相應(yīng)的處理:下載附件的數(shù)據(jù),保存到本地条辟,然后根據(jù)本地的文件URL創(chuàng)建UNNotificationAttachment實例對象黔夭,添加到通知里,并回調(diào)給系統(tǒng)。
以攜帶一張圖為例:
if let bestAttemptContent = bestAttemptContent {
// Modify the notification content here...
bestAttemptContent.title = "\(bestAttemptContent.title) [modified]"
print(bestAttemptContent.userInfo)
// 1. 獲取payload內(nèi)容
// 此處的 userInfo 即我們發(fā)送的Payload內(nèi)容
if let aps = bestAttemptContent.userInfo["aps"] as? [String: Any] {
// 2. 獲取到payload內(nèi)的圖片地址
if let imagePath = aps["image"] as? String {
// bestAttemptContent.body = "\(bestAttemptContent.body) +imagePath \(imagePath)"
if let url = URL(string: imagePath) {
// bestAttemptContent.body = "\(bestAttemptContent.body) +url \(url)"
// 3. 根據(jù)URL地址獲取圖片數(shù)據(jù)
if let data = try? Data.init(contentsOf: url) {
let path = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).first
// 4. 創(chuàng)建本地文件地址,最好在payload中添加一個文件名稱羡铲,或者文件格式宣增,在這里使用文件原名稱/格式進行存儲;這里直接寫死
let fileUrl = URL.init(fileURLWithPath: path! + "/image.jpg")
// bestAttemptContent.body = "\(bestAttemptContent.body) +file \(fileUrl)"
// 5. 保存圖片數(shù)據(jù)到本地
try? data.write(to: fileUrl)
// 6. 根據(jù)本地URL地址創(chuàng)建UNNotificationAttachment
if let att = try? UNNotificationAttachment(identifier: "imageattac", url: fileUrl, options: nil) {
bestAttemptContent.attachments = [att]
}
} /* if let data = end*/
} /* if let url = end*/
}/* if ler imagePath = end*/
}/* if let aps = end*/
// 7. 回調(diào)
contentHandler(bestAttemptContent)
}
實例代碼中的1.--7.是相關(guān)需要操作的步驟,還有注釋掉的bestAttemptContent.body = 部分代碼,因為無法打印log,為了能看到相關(guān)的信息先舷,我就把這些信息添加到body里面,然后顯示在通知里了甫窟。
這時密浑,再去發(fā)送一個通知:
在鎖屏頁面,或者彈框粗井,是這樣的
點擊查看尔破,或者下拉彈框街图,會顯示大圖
如果是其他的文件,例如視頻懒构、音頻文件餐济,都可以按此步驟來操作,下載的方式可以使用自己項目中使用的網(wǎng)絡(luò)框架進行胆剧。需要注意的是絮姆,此處下載的時間只有30s,所以附件一定要控制大小秩霍,如果在此時間內(nèi)沒有下載完成篙悯,或者下載失敗,將會以原通知的內(nèi)容進行推送铃绒,不含有附件鸽照。
PS: 這里需要注意,使用到這個功能的時候颠悬,一定要有訪問網(wǎng)絡(luò)的權(quán)限矮燎,也就是要在彈出那個網(wǎng)絡(luò)權(quán)限的選擇框之后。我在寫demo的時候赔癌,因為沒有用到網(wǎng)絡(luò)诞外,在此之前沒有申請網(wǎng)絡(luò)的授權(quán)訪問,所以一直沒有出現(xiàn)圖片灾票!