看之前如果你對(duì)iOS10 的推送還處于一片空白,建議先看
iOS 10 推送你玩過了嗎?
Notification Extension
iOS10 添加了很多的Extension,與通知相關(guān)的 extension 有兩個(gè):Service Extension 和 Content Extension。
我們先來了解一下Service Extension,這個(gè)東西主要是干啥的呢?
主要是,讓我們?cè)谑盏竭h(yuǎn)程推送的時(shí)候<注意哈,必須是遠(yuǎn)程推送>,展示之前對(duì)通知進(jìn)行修改,因?yàn)槲覀兪盏竭h(yuǎn)程推送之前會(huì)先去執(zhí)行Service Extension中的代碼。這樣就可以在收到遠(yuǎn)程推送展示之前為所欲為了。
用一張圖來表示下這種流程:
Service Extension能干啥?
舉個(gè)栗子:
<1>、通過遠(yuǎn)程推送,推送的內(nèi)容的
title="1"
,我可以在收到推送將要顯示之前將標(biāo)題修改成title="2"
,那么推送條展示的title就是2。<2>、第一點(diǎn)也就是舉個(gè)栗子,一般不會(huì)有這種需求,既然能修改內(nèi)容,那么可以在發(fā)送推送的時(shí)候發(fā)送一段用公鑰加密的內(nèi)容,然后設(shè)備收到推送之后,用私鑰進(jìn)行解密然后再去展示。有啥好處呢,這么折騰。有很多的推送用的是三方的<極光推送,友盟推送,百度推送等等>。這樣你推送的東西,就不會(huì)讓三方看到了。如果是金融之類的,要更注意保密吧。
<3>、當(dāng)遠(yuǎn)程推送需要展示多媒體的時(shí)候,也需要在這下載,下載完畢之后,獲取本地下載文件路徑再進(jìn)行展示。對(duì)下載附件多媒體得需要Service Extension這玩意兒。
介紹完畢,開始玩一下。
1、創(chuàng)建一個(gè)Service Extension
創(chuàng)建完畢之后看一下項(xiàng)目的變化
大概這幾個(gè)比較明顯的地方
創(chuàng)建完畢,看一下里面的相關(guān)的方法
方法override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void)
大概理解下:
收到一個(gè)遠(yuǎn)程推送的時(shí)候就會(huì)調(diào)用這個(gè)方法,你有30秒的時(shí)間來修改接收到的推送的內(nèi)容<你可以去修改通知的內(nèi)容,你也可以去下載推送的附件>,如果超過30秒了,你沒有做任何的處理,系統(tǒng)就會(huì)自動(dòng)的調(diào)用
override func serviceExtensionTimeWillExpire()
,如果你還不做出相應(yīng)的操作,那么將顯示最開始的通知的內(nèi)容。
怎么進(jìn)行測(cè)試呢?
第一步,選擇要測(cè)試的target,然后 run
第二步,選擇自己的app
第三步,來個(gè)小小的斷點(diǎn)
第四步,發(fā)個(gè)遠(yuǎn)程推送,本地推送自己可以嘗試,是沒反應(yīng)的。
2、玩一把
{
"aps":{
"alert":{
"title":"iOS 10 title",
"subtitle":"iOS 10 subtitle",
"body":"iOS 10 body"
},
"category":"saySomethingCategory",
"sound":"default",
"badge":3
}
}
推送收到了,但是沒有走斷點(diǎn)。
原因是推送的內(nèi)容中缺少一個(gè)字段
mutable-content 表示我們會(huì)在接收到通知時(shí)對(duì)內(nèi)容進(jìn)行更改。
{
"aps":{
"alert":{
"title":"iOS 10 title",
"subtitle":"iOS 10 subtitle",
"body":"iOS 10 body"
},
"mutable-content":1,
"category":"saySomethingCategory",
"sound":"default",
"badge":3
}
}
添加上之后再玩一把,在展示推送之前進(jìn)行走斷點(diǎn)了。
放過斷點(diǎn),我們發(fā)現(xiàn)標(biāo)題已經(jīng)被更改了。
3、嘗試更改其他的內(nèi)容
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]"
bestAttemptContent.body = "我是新修改的body"
bestAttemptContent.title = "我是新修改的title"
bestAttemptContent.subtitle = "我是subTitle"
contentHandler(bestAttemptContent)
}
}
更改推送內(nèi)容,有沒有這種需求呢?
我感覺有,比如你是一家金融公司,你給用戶單獨(dú)推送的東西不想讓別人抓包或者其他的方式看到,那么你可以在推送的時(shí)候進(jìn)行加密,然后到了客戶端之后再進(jìn)行解密。這樣做的話就比較安全一些。
4、展示遠(yuǎn)程推送過來的圖片
先說一下思路,收到推送之后,判斷有相關(guān)附件的話就去下載,下載完畢存儲(chǔ)到沙盒中,然后顯示。即時(shí)是過了30秒如果圖片沒下載下來,也會(huì)顯示最開始的推送的內(nèi)容的。
主要代碼:
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]"
bestAttemptContent.body = "我是新修改的body"
bestAttemptContent.title = "我是新修改的title"
bestAttemptContent.subtitle = "我是subTitle"
// 獲取相關(guān)的附件,看是不是有相關(guān)的附件
let userInfoDic = bestAttemptContent.userInfo
let apsDic:[AnyHashable : Any] = userInfoDic["aps"] as! [AnyHashable : Any]
if apsDic["my-attachment"] != nil{
// 如果說存在附件的話
loadAttachmentForUrlString(urlStr: apsDic["my-attachment"] as! String, completionHandler: { (attachment) in
if attachment != nil{
// 如果說 attachment 不為空的話
bestAttemptContent.attachments = [attachment!,attachment!]
}
contentHandler(bestAttemptContent)
})
}else{
// 如果說不存在附件的話
contentHandler(bestAttemptContent)
}
}
}
下載方法,下載完畢之后通過block進(jìn)行回調(diào)
// MARK:- 下載相關(guān)的附件信息
func loadAttachmentForUrlString(urlStr:String,completionHandler:@escaping CompletionHandlerBlock) -> Void {
let attachmentURL:URL = URL(string: urlStr)!
// 開啟線程去下載
DispatchQueue.global().async {
let urlSession = URLSession.shared.dataTask(with: attachmentURL, completionHandler: { (data, response, error) in
// 下載完畢,或者報(bào)錯(cuò),轉(zhuǎn)到主線程中
DispatchQueue.main.async {
var attachment : UNNotificationAttachment? = nil
if let data = data{
// 加工目的 url,將下載好的推送附件添加到沙盒中
let ext = (urlStr as NSString).pathExtension
let cacheURL = URL(fileURLWithPath: FileManager.default.cachesDirectory)
let finalUrl = cacheURL.appendingPathComponent(urlStr.md5).appendingPathExtension(ext)
print("finalUrl ************* \(finalUrl)")
// 將下載好的附件寫入沙盒
if let _ = try? data.write(to: finalUrl) {
// 寫入
attachment = try? UNNotificationAttachment(identifier: "pushAttachment", url: finalUrl, options: nil)
completionHandler(attachment)
}else{
completionHandler(attachment)
}
}else{
completionHandler(attachment)
}
}
})
urlSession.resume()
}
}
這里沒有去寫用SDWebImageView下載,也沒有用AFNetworking等三方庫去下載,我也想啊,但是報(bào)錯(cuò)。報(bào)錯(cuò)信息如下
有知道怎么解決的,跪求。
推送如下,收到推送去下載,但是說下載失敗,報(bào)錯(cuò)原因
MyServiceExtension[12788:2223445] App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure. Temporary exceptions can be configured via your app's Info.plist file.
解決方案:
終于的終于,實(shí)現(xiàn)效果:
當(dāng)然了對(duì)于這種推送附件緩存,建議每次推送的時(shí)候清理一下,不然越來越大了。并且還發(fā)現(xiàn)在不同的target下的沙盒地址是不一樣的
我感覺要是清理的話,可以在每次收到遠(yuǎn)程推送的時(shí)候清理一下。
遠(yuǎn)程推送視頻,音樂的,我木有相關(guān)的url資源,木有嘗試,不過應(yīng)該差不多。
有一些小伙伴問,為什么配置完畢之后回報(bào)錯(cuò),真機(jī)運(yùn)行的時(shí)候也報(bào)錯(cuò)
類似這樣的
myServiceExtension has conflicting provisioning settings.
myServiceExtension is automatically signed,
but code signing identity iPhone Developer: xxxxxxx has been manually specified. Set the code signing identity value to "iPhone Developer"
in the build settings editor, or switch to manual signing in the project editor.’
解決的辦法參考如下:
1、選擇 Automaticlly manage signing
選擇相關(guān)的team
2、signing的相關(guān)設(shè)置
都設(shè)置成Developer,這個(gè)真機(jī)調(diào)試,打包測(cè)試,上線這里都可以不用修改。Xcode會(huì)根據(jù)你的操作自動(dòng)配置相關(guān)的證書和Profile文件,前提是你的相關(guān)環(huán)境下的證書和Profile文件都是齊全的<這個(gè)應(yīng)該不是問題,不然你選擇當(dāng)前環(huán)境下的包是怎么打出來的>
最后,獻(xiàn)上參考Demo地址:https://github.com/RunOfTheSnail/PushDemo001
參考資料:
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
圖畫的不錯(cuò)
http://www.lxweimin.com/p/2f3202b5e758
http://www.cocoachina.com/ios/20161021/17820.html