iOS 10 的推送 User Notifications Framework

介紹

User Notifications Framework 是蘋果在 WWDC 2016 推出的。iOS 10 中以前雜亂的和通知相關的 API 都被統一了,現在開發者可以使用獨立的 UserNotifications.framework 來集中管理和使用 iOS 系統中通知的功能。在此基礎上,Apple 還增加了撤回單條通知,更新已展示通知,中途修改通知內容,在通知中展示圖片視頻,自定義通知 UI 等一系列新功能,非常強大。

iOS 10 以前的推送

iOS 10 以前推送分為 Local Notifications(本地推送) 和 Remote Notifications(遠程推送)。

本地推送:通過 App 本地定製,加入到系統的 Schedule 里,然後在指定的時間推送指定文字。

遠程推送:通過服務端向蘋果推送伺服器 Apple Push Notification Service (APNs) 發送 Notification Payload,之後 APNs 再將推送下發到指定設備的 指定 App 上。

User Notifications Framework

基本配置

如果只是簡單的本地推送,跳過 1 、2 步驟,直接到步驟 3。

1、 如果你的 App 有遠端推送的話,那你需要開發者賬號的,需要新建一個對應你 bundle 的 push 證書。 具體的證書製作請參考這裡

2、 Capabilities 中打開 Push Notifications 開關在 XCode7 中這裡的開關不打開,推送也是可以正常使用的,但是在 XCode8 中,這裡的開關必須要打開,不然會報錯:

Error Domain=NSCocoaErrorDomain Code=3000 "未找到應用程序的「aps-environment」的授權字元串" UserInfo={NSLocalizedDescription=未找到應用程序的「aps-environment」的授權字元串}

許可權申請

在使用 UserNotifications 框架的 API 的時候,首先要導入 UserNotifications 框架:

#import <UserNotifications/UserNotifications.h>

註冊推送

UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
[center requestAuthorizationWithOptions:(UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert) completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (!error)
{
NSLog(@"請求授權成功");
}
else
{
NSLog(@"請求授權失敗");
}
}];

Notification settings:之前註冊推送服務,用戶點擊了同意還是不同意,以及用戶之後又做了怎樣的更改我們都無從得知,現在 apple 開放了這個 API,我們可以直接獲取到用戶的設定信息了。注意 UNNotificationSettings 是只讀對象哦,不能直接修改!只能通過以下方式獲取

[center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
NSLog(@"%@", settings);
}];

列印

<UNNotificationSettings: 0x6000022f9dc0;
authorizationStatus: NotDetermined,
notificationCenterSetting: NotSupported,
soundSetting: NotSupported,
badgeSetting: NotSupported,
lockScreenSetting: NotSupported,
carPlaySetting: NotSupported,
criticalAlertSetting: NotSupported,
alertSetting: NotSupported,
alertStyle: None,
providesAppNotificationSettings: No>

Token Registration

[[UIApplication sharedApplication] registerForRemoteNotifications];

獲取設備的Device Token

//獲取DeviceToken成功
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
NSString *deviceString = [[deviceToken description] stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]];
deviceString = [deviceString stringByReplacingOccurrencesOfString:@" " withString:@""];
NSLog(@"deviceToken:%@",deviceString);
}

//獲取DeviceToken失敗
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
NSLog(@"[DeviceToken Error]:%@
",error.description);
}

接收推送的代理方法

// App處於前台接收通知時
// 只有app處於前台狀態下才會調用,後台狀態或者應用殺死下是不會調用這個方法的
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler

// App通知的點擊事件
// 用戶點擊消息才會觸發
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)())completionHandler

蘋果把本地通知跟遠程通知合二為一。區分本地通知跟遠程通知的類是UNPushNotificationTrigger.h 類中,UNPushNotificationTrigger 的類型是新增加的。

UNPushNotificationTrigger (遠程通知) 遠程推送的通知類型

UNTimeIntervalNotificationTrigger (本地通知) 一定時間之後,重複或者不重複推送通知。我們可以設置timeInterval(時間間隔)和repeats(是否重複)。

UNCalendarNotificationTrigger(本地通知) 一定日期之後,重複或者不重複推送通知 例如,你每天8點推送一個通知,只要dateComponents為8,如果你想每天8點都推送這個通知,只要repeats為YES就可以了。

UNLocationNotificationTrigger (本地通知)地理位置的一種通知,

當用戶進入或離開一個地理區域來通知。

內容

以前只能展示一條文字,現在可以有 title 、subtitle 以及 body 了。

定製方法如下:

//本地通知
UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
content.title = @"CALENDAR";
content.subtitle = @"Lunch";
content.body = @"Today at 12:00 PM";
content.badge = @1;

//遠程推送
{
"aps" : {
"alert" : {
"title" : "CALENDAR",
"subtitle" : "Lunch",
"body" : "Today at 12:00 PM"
},
"badge" : 1
},
}

Triggers

UNTimeIntervalNotificationTrigger 定時推送

UNCalendarNotificationTrigger 定期推送

UNLocationNotificationTrigger 定點推送

//60 秒後提醒
//timeInterval:單位為秒(s) repeats:是否循環提醒
UNTimeIntervalNotificationTrigger *trigger1 = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:60 repeats:NO];

// 在每周一早上 8:00 提醒
NSDateComponents *components = [[NSDateComponents alloc] init];
components.weekday = 2;
components.hour = 8;
UNCalendarNotificationTrigger *trigger3 = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:components repeats:YES];

//首先得導入#import <CoreLocation/CoreLocation.h>,不然會regin創建有問題。
CLLocationCoordinate2D center1 = CLLocationCoordinate2DMake(31.234567, 117.4567890);
CLCircularRegion *region = [[CLCircularRegion alloc] initWithCenter:center1 radius:500 identifier:@"桂林路"];
UNLocationNotificationTrigger *trigger4 = [UNLocationNotificationTrigger triggerWithRegion:region repeats:NO];

Add Request

NSString *requestIdentifier = @"sampleRequest";
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:requestIdentifier
content:content
trigger:trigger1];
[center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {

}];

推送小結

整個推送的過程如下

Local Notifications 通過定義 Content 和 Trigger 向 UNUserNotificationCenter 進行 request 這三部曲來實現。

Remote Notifications 則向 APNs 發送 Notification Payload 。

Notification Handling

設定了推送,然後就結束了?iOS 10 並沒有這麼簡單!

通過實現協議,使 App 處於前台時捕捉並處理即將觸發的推送:

@interface AppDelegate () <UNUserNotificationCenterDelegate>

- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler
{
completionHandler(UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionSound);
}

讓它只顯示 alert 和 sound ,而忽略 badge 。

Notification Management

徹底掌控整個推送周期:

Local Notification 通過更新 request

Remote Notification 通過新的欄位 apns-collapse-id

通過之前的 addNotificationRequest: 方法,在 id 不變的情況下重新添加,就可以刷新原有的推送。

NSString *requestIdentifier = @"sampleRequest";
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:requestIdentifier
content:newContent
trigger:newTrigger1];
[center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {

}];

刪除計劃的推送:

[center removePendingNotificationRequestsWithIdentifiers:@[requestIdentifier]];

此外 UNUserNotificationCenter.h 中還有諸如刪除所有推送、查看已經發出的推送、刪除已經發出的推送等等強大的介面。

刷新原有的推送後,在通知中心的顯示里,也會有相應的變化,這裡注意第 2 條信息,現在比分是 1:0

比分刷新後為 1:1,在不產生新的推送條目的情況下位置被前置了!

上面簡單介紹了 iOS 10 的新框架 User Notifications Framework,了解完 iOS 10 的框架之後,還要適配iOS 8 9 系統,是不是覺得很麻煩,筆者最近發現了一款 SDK ----MobPush,兼容 iOS 8-12 系統,接入非常簡單,3行代碼就可以搞定推送。

MPushNotificationConfiguration *configuration = [[MPushNotificationConfiguration alloc] init];
configuration.types = MPushAuthorizationOptionsBadge | MPushAuthorizationOptionsSound | MPushAuthorizationOptionsAlert;
[MobPush setupNotification:configuration];

同時,MobPush 支持多樣化推送場景、用戶分群、AB 測試、智能推送等等功能,還有完善的數據統計後台可以從多個維度實時了解 APP 和用戶的使用情況

了解更多


推薦閱讀:

TAG:推送(Push) | SDK | iOS |