本文參考了 http://www.jianshu.com/p/9b720efe3779和https://onevcat.com/2016/08/notification/兩篇文章。感謝。
本教程以貼代碼為主。盡可能直觀,少量說明。
注意:XCode8的需要手動開啟主target Capabilities中的Push Notification。
關於創建多個target後真機測試的證書問題,除了主target手動創建開發和發布證書,並設置了APNS證書外,其它均使用Automatically manage signing。
首先介紹一下本文涉及到UserNotifications的幾個主要類。
其中
[1]UNNotification主要是作為通知delegate方法的參數使用。包含UNNotificationRequest信息。
[2]UNNotificationAction是通知中添加的action,展示在通知欄的下方。默認以的button樣式展示。有一個文本輸入的子類UNTextInputNotificationAction。可以在點擊button之後彈出一個鍵盤,輸入信息。用戶點擊信息和輸入的信息可以在UNNotificationResponse中獲取。
[3]UNNotificationAttachment是新增的通知內容格式,可以設置圖像和視頻。Demo中使用說明。
[4]UNNotificationCategory是通知樣式類型。在注冊通知之後,展示通知之前,可以自定義通知樣式,並使用
[[UNUserNotificationCenter currentNotificationCenter] setNotificationCategories:[NSSet setWithObject:categoryNotification]]設置到通知中心中。根據通知內容中的categoryIdentifier使用不同的通知樣式。這裡需要注意:使用自定義的通知操作按鈕和通知Content可以設置為同一個category。
[5]UNNotificationContent通知的主體內容,原通知的title,sound,badge和新的attachments,lacnchImageName都在這裡進行設置,是創建一個通知的前提。
[6]UNNotificationRequest通知請求。當通知內容,觸發條件都准備好之後,需要包裝為一個通知請求,由通知中心來激活這個通知。
[7]UNNotificationResponse通知響應。作為通知的action被用戶觸發之後,App可以拿到的信息。和action對應,有普通的UNNotificationResponse和子類UNTextInputNotificationResponse。其中包括action的identifier和完整的UNNotification。子類UNTextInputNotificationResponse還包含userText,用戶輸入的內容。
[8]UNNotificationServiceExtension一個extension。用戶可以在收到特性的通知時,一般是遠程,並且該遠程通知的apns中包含一個mutable-content字段,值為1。極光示例如圖
你有30秒的時間處理這個通知,可以同步下載圖像和視頻到本地,然後包裝為一個UNNotificationAttachment扔給通知,這樣就能展示用服務器獲取的圖像或者視頻了。這裡需要注意:如果數據處理失敗,超時,extension會報一個崩潰信息,但是通知會用默認的形式展示出來,app不會崩潰。
[9]UNNotificationSetting沒使用,不評論。
[10]UNNotificationSound通知的聲音。可以直接使用聲音的name,而不是文件路徑。
[11]UNNotificationTrigger通知的觸發條件。本Demo僅使用了其中的延時觸發功能,其它諸如定時和地理圍欄的功能不做說明。地理圍欄能可以作為觸發條件,就減少了之前需要在地理圍欄的delegate中手動添加一個延遲的本地通知的問題。
[12]UNUserNotificationCenter通知中心。最主要的類,通知的注冊,激活,編輯,刪除等功能都由該類完成。
1、通知授權
通知授權部分包括了iOS7 - iOS10。授權方式此處分為兩種,一種是蘋果原生的注冊方法,另一種使用了極光推送的版本。
原生的注冊方法:
iOS 10之前的版本不受影響,10版本中使用UNUserNotificationCenter判斷用戶是否允許app接收通知。如果granted == false,建議彈框提示用戶開啟通知功能。第一行設置UNUserNotificationCenterDelegate的delegate,可以在AppDelegate中獲取兩個方法,分別為在app在活躍狀態下接收到通知和用戶點擊action進入app。
極光的注冊方法
極光需要輸入極光賬戶中的appKey等信息,此處參照了極光官方文檔。
2、通知注冊
通知注冊的方法在10中被保留,不做修改。
[[UIApplication sharedApplication] registerForRemoteNotifications];
3、獲取APNS Token
獲取Token的方法在10中被保留,不做修改。由於單一使用極光作為遠程推送,token提交部分只有極光的代碼。- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
// Apns注冊成功,該方法沒有沒有變化。
// 通過JPUSH上傳設備Token.
[JPUSHService registerDeviceToken:deviceToken];
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{
[JPUSHService handleRemoteNotification:userInfo];
}
不好意思。實在受夠了這個在線版本的圖片上傳。之後不好在貼圖。直接上代碼。大家湊合看吧。
4、App獲取通知信息。
在iOS10之前,使用didReceiveRemoteNotification:fetchCompletionHandler:方法獲取用戶信息。
在iOS10中,統一使用UNUserNotificationCenterDelegate的兩個delegate方法來獲取通知信息。
這裡需要注意:如果沒有設置UNUserNotificationCenterDelegate的delegate,仍然使用原方法獲取用戶信息。同時,在獲取遠程通知的時候,如何沒有帶mutable-content字段,也在被原方法獲取,即使設置了delegate。
本文只講在需要進app的cation時,觸發的event。
delegate方法。注意需要調用completionHandler()
原生版本:
// iOS10特性。App在前台獲取通知
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler {
completionHandler(UNNotificationPresentationOptionAlert);
}
// iOS10特性。點擊通知進入App
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)())completionHandler {
completionHandler()
}
極光版本:
#pragma mark - JPUSHRegisterDelegate
// 只有調用registerForRemoteNotificationConfig:delegate:方法才會激活該delegate。
// 一旦激活該delegate就不再觸發application:didReceiveRemoteNotification:fetchCompletionHandler:
// iOS10特性。App在前台獲取通知
- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(NSInteger options))completionHandler { completionHandler(UNNotificationPresentationOptionAlert); } // iOS10特性。點擊通知進入App - (void)jpushNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)())completionHandler { completionHandler() }
上面基本包括了一個iOS 10通知的使用。已經可以正常獲取到推送通知信息。
下面會根據Demo中的示例依次講解。主要就是貼代碼,大家可以直接下載Demo,在代碼中會有一些注意事項的說明。
本人寫代碼基本不寫注釋。匈牙利流。見諒。
示例順序如下
@"簡單的本地通知",
@"帶兩個Title的本地通知",
@"帶聲音的本地通知",
@"帶圖像的本地通知",
@"帶視頻的本地通知",
@"不進入應用的按鈕",
@"進入應用的按鈕",
@"帶文本輸入框的按鈕",
@"自定義通知欄UI",
@"隱藏系統默認消息框",
@"不進App-通知欄UI直接反饋用戶操作"
5、簡單的本地通知
這是一個最基本的通知激活方法。
從這裡可以看到,一個通知基本有content,request,trigger組成。其它的示例只是給content添加更多的內容。
所有的通知都是由[UNUserNotificationCenter currentNotificationCenter]激活。
UNMutableNotificationContent* content = [[UNMutableNotificationContent alloc] init]; content.body = @"Hello,world!"; UNTimeIntervalNotificationTrigger* trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:5 repeats:NO]; NSString* requestIdentifer = @"Request"; UNNotificationRequest* request = [UNNotificationRequest requestWithIdentifier:requestIdentifer content:content trigger:trigger]; [[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) { NSLog(@"Error%@", error); }];
6、帶兩個Title的本地通知
該通知攜帶兩個相對新的字段,title和subtitle,都是字符類型。作為標題顯示。
這兩個字段在iOS8.2之後的通知中被使用,但是只要在watch上的通知可以顯示出了。
通知樣式:
居然還是得帶圖。換七牛了。
講真,真不想上圖。可是突然發現字數不夠了。
7、帶聲音的本地通知
使用了新的類UNNotificationSound,添加通知的聲音。
該代碼中同時使用了badge。在Appdelegate中可以清除。
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:0];
8、帶圖像的本地通知
圖像必須是bundle包中的,可以下拉通知欄放大圖像。
9、帶視頻的本地通知
之後3個都是關於action的。
10、不進入應用的按鈕
11、進入應用的按鈕
兩者action的區別在UNNotificationActionOptions中。該枚舉分3種,分別為
需要解鎖顯示,紅色文字。點擊不會進app。
UNNotificationActionOptionAuthenticationRequired = (1 << 0),
黑色文字。點擊不會進app。
UNNotificationActionOptionDestructive = (1 << 1),
黑色文字。點擊會進app。
UNNotificationActionOptionForeground = (1 << 2),
12、帶文本輸入框的按鈕
其中UNTextInputNotificationAction是UNNotificationAction的子類,初始化方法中分別新增了,鍵盤右上角的點擊按鈕文本和文本輸入框的默認文字。
點擊action在AppDelegate的事件:
NSString* actionIdentifierStr = response.actionIdentifier;
if ([response isKindOfClass:[UNTextInputNotificationResponse class]]) {
NSString* userSayStr = [(UNTextInputNotificationResponse *)response userText];
}
UNNotificationContent* content = response.notification.request.content;
NSDictionary* userInfo = response.notification.request.content.userInfo;
UNNotificationAttachment* attachments = response.notification.request.content.attachments;
基本從以前可以獲取到通知的全部信息。
13、自定義的通知欄UI
需要新建一個Notification Content。可以創建多個,但是需要設定不同的category。參照Demo。同一個content可以設置多個category。
默認的NotificationContent的VC中,默認有兩個方法。分別為viewDidLoad和didReceiveNotification。前者渲染UI,後者獲取通知信息,更新UI控件中的數據。
14、隱藏默認的消息欄。
系統消息欄會默認出現在下方。如果你已經自定義的顯示的控件,就顯得多余,可以隱藏默認。
// 隱藏默認消息框。添加UNNotificationExtensionDefaultContentHidden屬性,Bool(YES).
15、不進App在通知欄上反饋用戶的操作。
需要執行UNNotificationContentExtension的delegate方法didReceiveNotificationResponse:completionHandler:
這裡注意:必須對全部的action進行處理。必須設置completion,否則通知不會消失。
創建通知代碼
處理通知的代碼。在自定義的NotificaitonContent中
16、獲取遠程通知後進行處理顯示。此處以遠程通知發送一個image的uri,通知顯示圖片為例。
需要添加一個新的target Notification Service extension。
這裡的extension需要在info.plist中設置HTTP。
希望對大家有幫助。
Demo地址:
github: https://github.com/JiLaqi/NotificationCenterDemo
qiniu:http://7xpxop.com1.z0.glb.clouddn.com/NotificationCenter.zip?attname=