一、概述
Apple早在iOS10就退出NotificationServiceExtension的擴(kuò)展,并不是必備項(xiàng)目,因此各家公司產(chǎn)品支持各不相同,主要取決于產(chǎn)品的實(shí)際需求是否需要。
2021年我所在項(xiàng)目的一個(gè)需求是:“推送內(nèi)容顯示圖片(title-image),即推送支持簡(jiǎn)圖”,這個(gè)需求就需要用到NotificationServiceExtension 的相關(guān)內(nèi)容。
百度有很多集成的教程,不知道為啥,很多都只說了其中一個(gè)片面,其原因在于很多都只是看了官網(wǎng)的教程,實(shí)際開發(fā)中遇到的問題沒有寫出來。
以下是相關(guān)筆記,
特別是擴(kuò)展是如何與宿主App的Target關(guān)聯(lián)的?
如何被打包進(jìn)宿主App的?
它在宿主App的包里面長(zhǎng)什么樣?
它是如何和宿主App一同提審?
二、NotificationServiceExtension原理篇
1、NotificationServiceExtension 的作用是什么?
NotificationServiceExtension屬于AppExtension(擴(kuò)展)的范疇,屬于官方推出的擴(kuò)展。同NotificationContentExtension一同豐富用戶的推送體驗(yàn),讓開發(fā)者可以本地?cái)r截和修改推送內(nèi)容的機(jī)會(huì),可以自定義自己的推送內(nèi)容展示樣式。大大提高了整體的用戶體驗(yàn)。
2、NotificationServiceExtension相關(guān)特性(官網(wǎng)翻譯)
只允許修改推送內(nèi)容,不能包含任何的UI顯示。
A Notification Service app extension doesn't present any UI of its own.開發(fā)者無法自己初始化,在推送到達(dá)的時(shí)候iOS系統(tǒng)會(huì)自動(dòng)創(chuàng)建
UNNotificationServiceExtension對(duì)象。開發(fā)者只能通過擴(kuò)展Target下的NotificationServiceExtension的子類來修改自己App推送的內(nèi)容。
You don't create UNNotificationServiceExtension objects yourself. Instead, the Xcode template for a Notification Service Extension target contains a subclass for you to modify.iOS收到App的推送的時(shí)候,系統(tǒng)自動(dòng)初始化
UNNotificationServiceExtension對(duì)象,然后回調(diào)給App的擴(kuò)展子類的方法didReceiveNotificationRequest:withContentHandler:。
When a remote notification for your app is received, the system loads your extension and calls its didReceiveNotificationRequest:withContentHandler: method響應(yīng)函數(shù)的操作時(shí)間只有30秒;如果未處理超時(shí)處理,系統(tǒng)會(huì)按照默認(rèn)顯示推送。
Your didReceiveNotificationRequest:withContentHandler: method has only about 30 seconds to modify the payload and call the provided completion handler. If your code takes longer than that, the system calls the serviceExtensionTimeWillExpire method, at which point you must return whatever you can to the system immediately. If you fail to call the completion handler from either method, the system displays the original contents of the notification.-
服務(wù)端推送的payload格式要求
必須是alert類型,aps字段必須包含有alert字段,alert里必須是title、subtitle、body任何一個(gè)。
The payload must include an alert dictionary with title, subtitle, or body information.aps字段里面必須有mutable-content字段,其值必須為1。
The remote notification’s aps dictionary includes the mutable-content key with the value set to 1.
3、UNNotificationServiceExtension工作原理篇
詳見鄙人另外整理筆記。AppExtension:擴(kuò)展的學(xué)習(xí)筆記
三、UNNotificationServiceExtension的實(shí)踐
1、前提
推送主工程必須開啟推送功能,證書也必須支持,bundleId不能包含通配符,這些是基礎(chǔ)知識(shí)。

2、創(chuàng)建
在項(xiàng)目工程中,新建Target的方式集成(一個(gè)工程允許存在多個(gè)Targets),如下

系統(tǒng)模板自動(dòng)創(chuàng)建:NotificationServiceExtension的文件夾、NotificationService : UNNotificationServiceExtension子類、info.plist配置文件。

其中info.plist配置文件,擴(kuò)展關(guān)鍵配置如下,id固定com.apple.usernotifications.service不能更改,class對(duì)應(yīng)子類類名。后續(xù)擴(kuò)展Target的相關(guān)配置都在這里面,需要網(wǎng)絡(luò)的需要開啟App Transport Security Settings的Allow Arbitrary Loads為YES。

2、主工程Target與擴(kuò)展Target的關(guān)系(關(guān)鍵的關(guān)鍵)
很多網(wǎng)上的教程都沒有說明這點(diǎn),以至于后續(xù)打包和提審都難以理解其原理。(網(wǎng)上很多直說無法單獨(dú)提審,必須與ContainApp一起提審。)
- 擴(kuò)展Target是通過 ”依賴的方式“ 的方式添加到主工程Target中。
查看主工程Target的BuildPhases的Dependencies關(guān)聯(lián)擴(kuò)展Target;同時(shí)多了個(gè)Embed App Extensions里面關(guān)聯(lián)擴(kuò)展的編譯產(chǎn)物.appex執(zhí)行文件。
0693088B-0E07-482C-A441-A68B6EC97031.png
-
擴(kuò)展最終被打包給
.appex的bundle包,同時(shí)被打包到ContainApp的包的Pluglns的目錄下。
824DCA63-95E5-41B1-A70D-64B1E2449D8B.png -
使用
Tree命令,看看.appex的bundle包的內(nèi)容:
419D7EDD-A72C-4020-9947-BB3CA2A9CDF6.png
3、調(diào)試
網(wǎng)上內(nèi)容也很多,主要是以下幾步:
擴(kuò)展Target和主工程Target必須配置不同的證書,且主工程開啟推送功能。
編譯的目標(biāo)順序
1、主工程編譯,真機(jī)運(yùn)行。
2、擴(kuò)展Target編譯運(yùn)行,選擇主工程App,Attachment連接啟動(dòng)。
3、模擬推送一波,UNNotificationServiceExtension的擴(kuò)展之類,斷點(diǎn)即可執(zhí)行。
調(diào)試一些問題
- 推送格式錯(cuò)誤,具體參見上面格式要求。
- 對(duì)于舊工程,后續(xù)接入者莫名其妙的無法調(diào)試,可以重新刪掉Target,重建一個(gè)名字一樣的擴(kuò)展。
4、打包&提審
上面可知,擴(kuò)展的Target是通過依賴主工程Target的方式一同編譯打包的,因此后續(xù)打包提審的時(shí)候只要對(duì)應(yīng)的配置好證書,打包主工程App,然后提審就行。

As with any target, an extension target specifies settings and files that combine to build a product within your app project.
Each template includes extension point–specific implementation files and settings, and produces a separate binary that gets added to your containing app’s bundle.
注意:打包導(dǎo)出的時(shí)候,需要同時(shí)勾選主Target和擴(kuò)展Target的對(duì)應(yīng)證書。

四、帶圖片的推送需求實(shí)現(xiàn)
”帶圖片的推送“需求具體實(shí)現(xiàn),主要是把圖片自行下載,然后保存,添加到對(duì)應(yīng)的類中屬性即可。
UNNotificationAttachment *resourceAttachment =
[UNNotificationAttachment attachmentWithIdentifier:@"photo" URL:obj options:nil error:&attachmentErrer];
if (resourceAttachment && !attachmentErrer) {
strongSelf.bestAttemptContent.attachments = @[resourceAttachment];
}
本文不再累贅,參見iOS10推送必看UNNotificationServiceExtension,或者自行百度。
五、UNNotificationServiceExtension 其他
- 與主工程代碼復(fù)用,同AppExtension。
- 與主工程的數(shù)據(jù)共享,同AppExtension。
具體見AppExtension:擴(kuò)展的學(xué)習(xí)筆記
參考
官網(wǎng)-UNNotificationServiceExtension
官網(wǎng)-Modifying Content in Newly Delivered Notifications


