大夥久等啦~這絕對是最全最詳細的 UNNotificationContentExtension講解喲~
這篇文章中,我會給大家補充完推送內容的後續部分,希望大家看完這篇文章後,便可以輕鬆的玩轉推送了。
1、UNNotificationContentExtension
1.1、UNNotificationContentExtension簡介
簡單來說,UNNotificationContentExtension這個類,也是iOS10推送的新特性,官方文件用這麼一句話,簡單的解釋了一下,Presents a custom interface for a delivered local or remote notification.(當你收到遠端或者本地通知的時候,彈出一個自定義介面)。效果如下圖所示
還有下圖
上面的兩張圖就是我們將要做出的效果,在自定義View的區域,你可以放上個視訊,放上個日曆,放上個顯示地理位置的Label,總而言之,我們可以自定義View!
1.2、如何新建一個UNNotificationContentExtension
建立這個UNNotificationContentExtension的Target,類似於建立UNNotificationServiceExtension的步驟。
第一步:建立
之後便可以看到生成了這些內容
1.3、如何使用以及相關Demo
說到如何使用這個類,我們就一定要先說一下,系統幫我們生成的這幾個檔案分別代表了什麼意思。
>0.Info.plist
在這個NSExtensionAttributes的字典下面,我們有三個屬性可以新增
一.UNNotificationExtensionCategory.
(必須要有,系統已經建立好)
解釋:對應這個key的值,可以是一個字串,也可以是一個陣列,每一個字串都是一個identifier,這個identifier對應著每一個UNMutableNotificationContent的categoryIdentifier的屬性。
簡單來說,就是在收到通知的時候,我們可以讓伺服器把這個通知的categoryIdentifier帶上,作用是,我們可以根據視訊,音樂,圖片,來分別自定義我們的通知內容。不同的分類識別符號,也會在我們講到UNNotificationAction的時候,幫助我們區分是什麼型別的通知,方便我們對不同型別的通知做出不同的操作行為。上面的截圖中,我是一個字串的形式。下圖為陣列形式:
使用的時候,我們參照如下程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
// 1.這個方法是UNNotificationServiceExtension類裡面的方法,可以參照我上一篇文章講的UNNotificationServiceExtension,我要在這裡重寫我的通知。 - (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"]]; !!!!! 這裡是重點!!!!!!!!!!!! // 我在這裡寫死了category1,其實在收到系統推送時,每一個推送內容最好帶上一個catagory,跟伺服器約定好了,這樣方便我們根據categoryIdentifier來自定義不同型別的檢視,以及action self.bestAttemptContent.categoryIdentifier = @"category1"; } |
大家注意上面的
1 2 3 |
!!!!! 這裡是重點!!!!!!!!!!!! // 我在這裡寫死了category1,其實在收到系統推送時,每一個推送內容最好帶上一個catagory,跟伺服器約定好了,這樣方便我們根據categoryIdentifier來自定義不同型別的檢視,以及action self.bestAttemptContent.categoryIdentifier = @"category1"; |
這裡設定categoryIdentifier,最好讓伺服器的推送內容帶上這個,然後我們好更加的定製化。不建議本地寫死。
具體可以參考我的demo地址
二.UNNotificationExtensionInitialContentSizeRatio.
(必須要有,系統已經建立好)
解釋:這個值的型別是一個浮點型別,代表的是高度與寬度的比值。系統會使用這個比值,作為初始化view的大小。舉個簡單的例子來說,如果該值為1,則該檢視為正方形。如果為0.5,則代表高度是寬度的一半。
注意這個值只是初始化的一個值,在這個擴充套件新增後,可以重寫frame,展示的時候,在我們還沒開啟這個檢視預覽時,背景是個類似圖片佔位的灰色,那個灰色的高度寬度之比,就是通過這個值來設定。
三.UNNotificationExtensionDefaultContentHidden.
(可選)
解釋:這個值是一個BOOL值,當為YES時,會隱藏上方原本推送的內容檢視,只會顯示我們自定義的檢視。(因為在自定義檢視的時候,我們可以取得推送內容,然後按照我們想要的佈局,展示出來)如果為NO時(預設為NO),推送檢視就會既有我們的自定義檢視,也會有系統原本的推送內容檢視(這裡附件是不會顯示的,只會顯示body裡面的文字喲)
四.至於NSExtensionMainStoryboard以及NSExtensionPointIdentifier,系統預設生成,大家直接用就好,如果需要更改的,只能更改使用的storyboard的名字(不過應該沒人會把系統的刪除在建立一個吧 O(∩_∩)O)
>1.MainInterface.storyboard
這個就是個簡單的storyboard檔案,內部有一個View,這個View就是在上面的圖層中的自定義View檢視了。它與NotificationViewController所繫結。
>2.NotificationViewController
這是是系統幫我們預設建立了一個控制器,繼承UIViewController,其實就是一個控制器啦。
說道這個控制器我們需要講解一個方法:
- 遵守UNNotificationContentExtension的協議,我們需要用到一下的方法
1 2 |
// 這個方法是說,只要你收到通知,並且保證categoryIdentifier的設定,跟info.plist裡面設定的一樣,你就會呼叫這個方法。注意:一個會話的多個通知,每個通知收到時,都可以呼叫這個方法。 - (void)didReceiveNotification:(UNNotification *)notification; |
使用如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
- (void)didReceiveNotification:(UNNotification *)notification { 這個方法,可以給自己的控制元件賦值啊,調整frame啊等等,我在這裡列印出來了通知的內容,供大家使用。 NSDictionary *dict = notification.request.content.userInfo; // 這裡可以把列印的所有東西拿出來 NSLog(@"%@",dict); /****************************列印的資訊是************ aps = { alert = "This is some fancy message."; badge = 1; from = "大家好,我是徐不同"; imageAbsoluteString = "http://upload.univs.cn/2012/0104/1325645511371.jpg"; "mutable-content" = 1; sound = default; }; } *******************************************/ } |
說到這裡,簡單的UNNotificationContentExtension已經說完了,我在給大家補充一點。在UNNotificationContentExtension.h中,有著這麼一個列舉
1 2 3 4 5 6 7 8 |
typedef NS_ENUM(NSUInteger, UNNotificationContentExtensionMediaPlayPauseButtonType) { // 沒有播放按鈕 UNNotificationContentExtensionMediaPlayPauseButtonTypeNone, // 有播放按鈕,點選播放之後,按鈕依舊存在,類似音樂播放的開關 UNNotificationContentExtensionMediaPlayPauseButtonTypeDefault, // 有播放按鈕,點選後,播放按鈕消失,再次點選暫停播放後,按鈕恢復 UNNotificationContentExtensionMediaPlayPauseButtonTypeOverlay, } |
看到這麼列舉,大家一定納悶怎麼使用啊。請看下面的幾個屬性
1 2 3 4 5 6 7 8 9 |
// 設定播放按鈕的屬性 @property (nonatomic, readonly, assign) UNNotificationContentExtensionMediaPlayPauseButtonType mediaPlayPauseButtonType; // 設定播放按鈕的frame @property (nonatomic, readonly, assign) CGRect mediaPlayPauseButtonFrame; // 設定播放按鈕的顏色 @property (nonatomic, readonly, copy) UIColor *mediaPlayPauseButtonTintColor; // 開始跟暫停播放 - (void)mediaPlay; - (void)mediaPause; |
還有以下的類,這個類雖然也有開始播放跟結束播放的方法,不過要注意,這個是屬於NSExtensionContext的,而上面我們講的方法是UNNotificationContentExtension協議方法裡的。大家要注意。
1 2 3 4 5 6 |
@interface NSExtensionContext (UNNotificationContentExtension) // 控制播放 - (void)mediaPlayingStarted // 控制暫停 - (void)mediaPlayingPaused @end |
看到這些屬性,想要知道如何使用,請看我下面的步驟:
分析:
首先這些屬性都是readonly的,所以直接用self.屬性去修改肯定是報錯的,所以我們能用的就只有get方法了。
其次:根據button的型別,我們可以聯想到,如果button沒有,這個播放開始暫停的方法也沒用了。如果有button,自然我們就有了播放的操作,聯想別的UI空間,我們得出了一定要重寫它的frame,來確定他的位置。設定顏色,來設定它的顯示顏色。設定button的型別,讓他顯示出來。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// 返回預設樣式的button - (UNNotificationContentExtensionMediaPlayPauseButtonType)mediaPlayPauseButtonType { return UNNotificationContentExtensionMediaPlayPauseButtonTypeDefault; } // 返回button的frame - (CGRect)mediaPlayPauseButtonFrame { return CGRectMake(100, 100, 100, 100); } // 返回button的顏色 - (UIColor *)mediaPlayPauseButtonTintColor{ return [UIColor blueColor]; } |
通過上面的程式碼,我們的button已經可以顯示出來了。如下圖(請忽略下面的策略等按鈕):
具體位置,大家可以通過重寫frame來確定button的位置。
當我們點選這個藍色button的時候,便可以執行一些播放暫停操作了,如下
1 2 3 4 5 6 7 8 |
- (void)mediaPlay{ NSLog(@"mediaPlay,開始播放"); } - (void)mediaPause{ NSLog(@"mediaPause,暫停播放"); } |
說道這裡,還少說一個地方,那就是NSExtensionContext類的播放暫停事件我們需要什麼時候呼叫呢?
經過我的研究,可以這麼使用,如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
- (void)mediaPlay{ NSLog(@"mediaPlay,開始播放"); // 點選播放按鈕後,4s後暫停播放 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(4.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [self.extensionContext mediaPlayingPaused]; }); } - (void)mediaPause{ NSLog(@"mediaPause,暫停播放"); // 點選暫停按鈕,10s後開始播放 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [self.extensionContext mediaPlayingStarted]; }); } |
這裡需要說幾個注意點
1.在這個控制器中,我們可以直接電泳self.extensionContext,來呼叫它的播放暫停方法。
2.呼叫這個播放暫停方法,並不會重新呼叫- (void)mediaPlay{}
或者- (void)mediaPause{}
,只能單純的呼叫。經過我的測試,
1 2 3 4 5 6 7 |
- (void)mediaPlayingStarted{ NSLog(@"主動呼叫開始的方法"); } - (void)mediaPlayingPaused { NSLog(@"主動呼叫暫停的方法"); } |
用上述程式碼,是監聽不到方法點選的喲~
有了自定義內容,自然也就有了自定義的action(行為),我明日補上~謝謝大家咯~
如果你喜歡我的文章,不要忘記關注我,謝謝大家了~
另外如果你要轉載,希望可以註明出處,我會寫出更多更好的文章,來回饋大家~