在這篇文章,我會給大家講一講更高級一點的,定制化更高的遠程通知。其中會補充我之前沒講的遠程推送(多媒體)通知,以及UNNotificationServiceExtension,UNNotificationContentExtension,UNNotificationAction的相關類。相信大家看了這篇文章,雖不能說對蘋果的遠程推送了如指掌,但是也可以做一些基本的擴展咯~
1、UNNotificationServiceExtension
1.1 UNNotificationServiceExtension簡介
UNNotificationServiceExtension是iOS10推出后的一個新特性,先看這張圖:
從這張圖上,我們可以看到,原先直接從APNs推送到用戶手機的消息,中間添加了ServiceExtension處理的一個步驟(當然你也可以不處理),通過這個ServiceExtension,我們可以把即將給用戶展示的通知內容,做各種自定義的處理,最終,給用戶呈現一個更為豐富的通知,當然,如果網絡不好,或者附件過大,可能在給定的時間內,我們沒能將通知重新編輯,那么,則會顯示發過來的原版通知內容。
那么ServiceExtension可以做什么呢?它的意義是什么呢?我總結了幾點:
1、安全
安全總是擺在第一位的,從iOS9開始,蘋果鼓勵我們使用更為安全的https協議可以看的出來,蘋果公司是對安全很重視的一家公司,為什么在這里我會提到安全呢?是因為之前我們的推送內容,不管是通過第三方,還是通過蘋果自帶的通知處理,如果讓有心人對數據做一次攔截,抓個包啥的,我們推送的內容就會完全暴露,當然有的同學說,我可以加密啊~但是不知道大家有沒有想過,如果數據加密,那通知欄會怎么展示呢?(你千萬別跟我說你把所有的遠程推送變成本地通知。。)通過此次這次增加的UNNotificationServiceExtension的類,便可以更好的幫助我們實現數據的加密。
它的原理便是在收到通知后的最多30s內,你可以把你的通知內容,解密后,在重新展示在用戶的通知攔上。
2、內容的豐富
之前的通知展示內容比較少,以至于被各種廣告提醒占據了。這次蘋果新添加的附件通知,結合上通知拓展類,便可以給用戶展現出一個有著豐富內容的通知。比如,一個小短片的某一秒的畫面啊(這里要強烈鄙視各大平臺的某些電影預覽圖),又或者是配上一些小圖片啊(通過服務器傳來的imaUrl)等方式來吸引用戶,誘導用戶點開你的通知,促使用戶會使用你的App。其實推送這個功能,雖然有的人會關閉,但是大部分的人還是開啟的,所以說推送這個市場還是很大的喲~靈活利用推送,會讓你的程序擁有無限的可能。
1.2、如何新建一個UNNotificationServiceExtension
首先,我們不能通過創建UNNotificationServiceExtension的類來使用服務擴展,我們應當創建一個Target,這個Target自帶一個模板,其中有2個方法是系統會自己調用的,如下:
//??你需要通過重寫這個方法,來重寫你的通知內容,也可以在這里下載附件內容
-?(void)didReceiveNotificationRequest:(UNNotificationRequest?*)request?withContentHandler:(void?(^)(UNNotificationContent?*contentToDeliver))contentHandler;
//??如果處理時間太長,等不及處理了,就會把收到的apns直接展示出來
-?(void)serviceExtensionTimeWillExpire;
開始跟著我創建一個UNNotificationServiceExtension吧。
新建Target
選擇如圖所示:
然后寫名字,下一步,即可
此時我們的目錄結構里面,已經多出了一個文件夾了。
都多了一個myTest。
注意看上圖,這里的bundleID是你的工程名字的bundleID加上.名稱。
不要修改,系統創建的時候就創建好了,不過我還是給大家說一下這個格式
如果你的工程的BundleID是coderxu.pushDemo,則這個擴展的BundleID就是coderxu.pushDemo.mytest,最后的后綴,是看咱們創建服務擴展時候的名字。其他的小細節,大家可以看看。
到這一步,我們就新建了一個服務通知類的擴展。
1.3、如何使用以及相關Demo
在使用這個類的時候,我重寫了以下代碼,大家可以先看下:
(1). 這是處理通知內容重寫的方法:
-?(void)didReceiveNotificationRequest:(UNNotificationRequest?*)request?withContentHandler:(void?(^)(UNNotificationContent?*?_Nonnull))contentHandler?{
self.contentHandler?=?contentHandler;
//?copy發來的通知,開始做一些處理
self.bestAttemptContent?=?[request.content?mutableCopy];
//?Modify?the?notification?content?here...
self.bestAttemptContent.title?=?[NSString?stringWithFormat:@"%@?[modified]",?self.bestAttemptContent.title];
//?重寫一些東西
self.bestAttemptContent.title?=?@"我是標題";
self.bestAttemptContent.subtitle?=?@"我是子標題";
self.bestAttemptContent.body?=?@"來自徐不同";
//?附件
NSDictionary?*dict?=??self.bestAttemptContent.userInfo;
NSDictionary?*notiDict?=?dict[@"aps"];
NSString?*imgUrl?=?[NSString?stringWithFormat:@"%@",notiDict[@"imageAbsoluteString"]];
if?(!imgUrl.length)?{
self.contentHandler(self.bestAttemptContent);
}
[self?loadAttachmentForUrlString:imgUrl?withType:@"png"?completionHandle:^(UNNotificationAttachment?*attach)?{
if?(attach)?{
self.bestAttemptContent.attachments?=?[NSArray?arrayWithObject:attach];
}
self.contentHandler(self.bestAttemptContent);
}];
}
(2). 這是下載附件通知的方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27-?(void)loadAttachmentForUrlString:(NSString?*)urlStr
withType:(NSString?*)type
completionHandle:(void(^)(UNNotificationAttachment?*attach))completionHandler{
__block?UNNotificationAttachment?*attachment?=?nil;
NSURL?*attachmentURL?=?[NSURL?URLWithString:urlStr];
NSString?*fileExt?=?[self?fileExtensionForMediaType:type];
NSURLSession?*session?=?[NSURLSession?sessionWithConfiguration:[NSURLSessionConfiguration?defaultSessionConfiguration]];
[[session?downloadTaskWithURL:attachmentURL
completionHandler:^(NSURL?*temporaryFileLocation,?NSURLResponse?*response,?NSError?*error)?{
if(error?!=?nil)?{
NSLog(@"%@",?error.localizedDescription);
}else{
NSFileManager?*fileManager?=?[NSFileManager?defaultManager];
NSURL?*localURL?=?[NSURL?fileURLWithPath:[temporaryFileLocation.path?stringByAppendingString:fileExt]];
[fileManager?moveItemAtURL:temporaryFileLocation?toURL:localURL?error:&error];
NSError?*attachmentError?=?nil;
attachment?=?[UNNotificationAttachment?attachmentWithIdentifier:@""URL:localURL?options:nil?error:&attachmentError];
if(attachmentError)?{
NSLog(@"%@",?attachmentError.localizedDescription);
}
}
completionHandler(attachment);
}]?resume];
}
(3)判斷文件類型的方法
1
2
3
4
5
6
7
8
9
10
11
12
13-?(NSString?*)fileExtensionForMediaType:(NSString?*)type?{
NSString?*ext?=?type;
if([type?isEqualToString:@"image"])?{
ext?=?@"jpg";
}
if([type?isEqualToString:@"video"])?{
ext?=?@"mp4";
}
if([type?isEqualToString:@"audio"])?{
ext?=?@"mp3";
}
return[@"."stringByAppendingString:ext];
}
第一段代碼主要講通知內容的重組,邏輯就是有附件的url,我就下載,如果沒有url我就直接展示通知。
第二段代碼主要講的是,用系統自帶類,下載圖,存圖,找到filePath,創建通知的附件內容。(創建附件的url,必須是一個文件路徑,也就是說,必須下載下,才能獲取文件路徑,開頭是file://)
第三段的代碼主要講判斷文件的后綴類型,然后前端好處理。這里我的代碼是寫死了,因為我就測試一張圖。最好的方式是服務器返回的 推送內容中,帶有附件的類型。我的iOS開發 iOS10推送必看(高階1)一文中,有講多媒體附件的類型,以及相關的大小限制。
這里強烈建議,處理推送內容的時候,讓服務器帶上文件類型。重要的事情說三遍
這里強烈建議,處理推送內容的時候,讓服務器帶上文件類型。重要的事情說三遍
這里強烈建議,處理推送內容的時候,讓服務器帶上文件類型。重要的事情說三遍
在補充一些問題
1.在這個推送服務的擴展類中,為什么我使用了系統自帶類下載,沒有使用AFN?
答:不知道為什么,導入AFN后總是出現各種編譯報錯啊。主要涉及這幾個情況
1.用cocoapods導入AFN,在類引入AFN,編譯報錯!!
2.手動拖拽AFN進工程(不勾選),在類引入AFN,編譯報錯!!
3.手動拖拽AFN進工程(勾選),直接編譯報錯!!
4.下載用通知回調的方式(慢,線程不確定)
最后我就選擇這個block回調,系統類下載的方式,來下載通知中的附件。
以下是一些錯誤的截圖:(可以不看)
2.如果調試這個通知擴展類,為什么我跑程序的時候,打斷點無反應?
答:這是因為你跑的target不對,正確的做法是,跑正確的target,具體如下圖:
選擇你的程序Target
這個時候,大家在打斷點,就可以啦~
最后,在附上推送的內容格式。
推送內容格式如下:
{
"aps":?{
"alert":?"This?is?some?fancy?message.",
"badge":?1,
"sound":?"default",
"mutable-content":?"1",
"imageAbsoluteString":?"http://upload.univs.cn/2012/0104/1325645511371.jpg"
}
}
這里我們要注意一定要有"mutable-content": "1",以及一定要有Alert的字段,否則可能會攔截通知失敗。(蘋果文檔說的)。除此之外,我們還可以添加自定義字段,比如,圖片地址,圖片類型,大家慢慢摸索下吧~有問題可以留言喲~
這一章的最后,附上成功推送的展示圖:
稍后補充以下內容~
#?2、UNNotificationContentExtension
##?2.1、UNNotificationContentExtension簡介
##?2.2、如何新建一個UNNotificationContentExtension
##?2.3、如何使用以及相關Demo
#?3、UNNotificationAction
##?3.1、UNNotificationAction簡介
##?3.2、如何新建一個UNNotificationAction
##?3.3、如何使用以及相關Demo
如果你喜歡我的文章,不要忘記關注我,謝謝大家了~
另外如果你要轉載,希望可以注明出處,我會寫出更多更好的文章,來回饋大家~
重要的事情說三遍,demo地址
重要的事情說三遍,demo地址
重要的事情說三遍,demo地址