iOS 遠端通知
級別: ★★☆☆☆
標籤:「iOS通知」「iOSPush」「遠端通知」
作者: dac_1033
審校: QiShare團隊
iOS中的通知(Notification)分為兩種:
1. iOS 本地通知
2. iOS 遠端通知
3. iOS 通知擴充套件
iOS中的通知包括本地通知和遠端通知,兩種通知在iOS系統中通過橫幅或者彈出提醒兩種形式來告訴使用者,點選系統彈出的通知會開啟應用程式。
今天主要介紹iOS端關於遠端通知的相關功能及操作。
遠端通知
遠端通知是通過蘋果的APNs(
Apple Push Notification server
)傳送到App,而APNs必須先知道使用者裝置的地址,然後才能向該裝置傳送通知。此地址採用裝置令牌的形式,該裝置令牌對於裝置和應用程式都是唯一的(即device token)。在啟動時,App
與APNs
通訊並接收device token
,然後將其轉發到App Server
,App Server
將包含該令牌及要傳送的通知訊息傳送至APNs
。(蘋果官網APNs概述)
遠端通知的傳遞涉及幾個關鍵元件:
- App Server
- Apple推送通知服務(APNs)
- 使用者的裝置(包括iPhone、iPad、iTouch、mac等)
- 相應的App
蘋果官方提供的遠端通知的傳遞示意圖如下:
遠端通知中各關鍵元件之間的互動細節:
準備工作:
(1)在蘋果開發者賬號中建立的App ID不能使用通配ID
,並且在所建立的APP ID的配置項中選擇Push Notifications
服務,App使用沒有選擇該服務的App ID
所生成的推送證照和配置檔案時,無法完成註冊遠端通知;
(2)當前工程配置中的Bundle Identifier
必須和生成配置檔案使用的APP ID
完全一致;
(3)當前工程配置中的“Capabilities”需設定為ON
;
(4)遠端推送必須真機除錯,模擬器無法獲取得到device token
。
詳細步驟:
- 在AppDelegate中註冊APNs訊息
-(void)registerRemoteNotification {
if ([[UIDevice currentDevice].systemVersion floatValue] >= 10.0) {
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0 // Xcode 8編譯會呼叫
if (@available(iOS 10.0, *)) {
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
[center requestAuthorizationWithOptions:(UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionCarPlay) completionHandler:^(BOOL granted, NSError *_Nullable error) {
if (!error) {
NSLog(@"request notification authorization succeeded!");
}
}];
}
[[UIApplication sharedApplication] registerForRemoteNotifications];
#else // Xcode 7編譯會呼叫
UIUserNotificationType types = (UIUserNotificationTypeAlert | UIUserNotificationTypeSound | UIUserNotificationTypeBadge);
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:types categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
[[UIApplication sharedApplication] registerForRemoteNotifications];
#endif
} else {
UIUserNotificationType types = (UIUserNotificationTypeAlert | UIUserNotificationTypeSound | UIUserNotificationTypeBadge);
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:types categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
[[UIApplication sharedApplication] registerForRemoteNotifications];
}
}
- App獲取
device token
- 在註冊遠端通知之後,獲取
device token
成功回撥:
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken;
- 獲取
device token
失敗:
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error;
App將
device token
傳送給App Server
只有蘋果公司知道device token
的生成演算法,保證唯一,device token
在App重灌等情況時會變化,因此為確保device token
變化後App仍然能夠正常接收伺服器端傳送的通知,建議每次應用程式啟動都重新獲得device token
,並傳給App Server
。App Server根據最新的
device token
將要推送的訊息傳送給APNs
將指定device token和訊息內容傳送給APNs
時,訊息內容的格式必須完全按照蘋果官方的訊息格式組織訊息內容,點選檢視遠端通知訊息的欄位、建立遠端通知訊息。
訊息格式的例子如下:
{"aps":{"alert":{"title":"通知的title","subtitle":"通知的subtitle","body":"通知的body","title-loc-key":"TITLE_LOC_KEY","title-loc-args":["t_01","t_02"],"loc-key":"LOC_KEY","loc-args":["l_01","l_02"]},"sound":"sound01.wav","badge":1,"mutable-content":1,"category": "realtime"},"msgid":"123"}
APNs
根據device token
查詢相應裝置,並推送訊息
一般情況APNs可以根據deviceToken
將訊息成功推送到相應裝置中,但也存在使用者解除安裝程式等原因導致推送訊息失敗的情況,這時App
服務端會收到APNs
返回的錯誤資訊)。AppDelegate.m
中的回撥方法
// iOS<10時,且app被完全殺死
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;
// 注:iOS10以上,如果不使用UNUserNotificationCenter,將走此回撥方法
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo;
// iOS7及以上系統
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler;
// iOS>=10: App在前臺獲取到通知
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler;
// iOS>=10: 點選通知進入App時觸發(殺死/切到後臺喚起)
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler;
註冊遠端通知及解析通知資料的程式碼如下:
#import "AppDelegate.h"
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
#import <UserNotifications/UserNotifications.h>
#endif
@interface AppDelegate () <UNUserNotificationCenterDelegate>
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// 註冊APNs
[self registerRemoteNotifications];
return YES;
}
- (void)registerRemoteNotifications {
if ([[UIDevice currentDevice].systemVersion floatValue] >= 10.0) {
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0 // Xcode 8編譯會呼叫
if (@available(iOS 10.0, *)) {
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
[center requestAuthorizationWithOptions:(UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionCarPlay) completionHandler:^(BOOL granted, NSError *_Nullable error) {
if (!error) {
NSLog(@"request authorization succeeded!");
}
}];
} else {
// Fallback on earlier versions
}
[[UIApplication sharedApplication] registerForRemoteNotifications];
#else // Xcode 7編譯會呼叫
UIUserNotificationType types = (UIUserNotificationTypeAlert | UIUserNotificationTypeSound | UIUserNotificationTypeBadge);
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:types categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
[[UIApplication sharedApplication] registerForRemoteNotifications];
#endif
} else if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) {
UIUserNotificationType types = (UIUserNotificationTypeAlert | UIUserNotificationTypeSound | UIUserNotificationTypeBadge);
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:types categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
[[UIApplication sharedApplication] registerForRemoteNotifications];
} else {
UIRemoteNotificationType apn_type = (UIRemoteNotificationType)(UIRemoteNotificationTypeAlert |
UIRemoteNotificationTypeSound |
UIRemoteNotificationTypeBadge);
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:apn_type];
}
}
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
// 獲取並處理deviceToken
NSString *token = [[deviceToken description] stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]];
token = [token stringByReplacingOccurrencesOfString:@" " withString:@""];
DLog(@"---DeviceToken--->> %@\n", token);
}
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
DLog(@"---register RemoteNotifications failed---\n%@", error);
}
// 注:iOS10以上,如果不使用UNUserNotificationCenter,將走此回撥方法
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
// iOS6及以下系統
if (userInfo) {
if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) {// app位於前臺通知
NSLog(@"app位於前臺通知(didReceiveRemoteNotification:):%@", userInfo);
} else {// 切到後臺喚起
NSLog(@"app位於後臺通知(didReceiveRemoteNotification:):%@", userInfo);
}
}
}
// 注:
// 1. 該回撥方法,App殺死後並不執行;
// 2. 該回撥方法,會與application:didReceiveRemoteNotification:互斥執行;
// 3. 該回撥方法,會與userNotificationCenter:willPresentNotification:withCompletionHandler:一併執行;
// 4. 該回撥方法,會與userNotificationCenter:didReceiveNotificationResponse::withCompletionHandler:一併執行。
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler NS_AVAILABLE_IOS(7_0) {
// iOS7及以上系統
if (userInfo) {
if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) {// app位於前臺通知
NSLog(@"app位於前臺通知(didReceiveRemoteNotification:fetchCompletionHandler:):%@", userInfo);
} else {// 切到後臺喚起
NSLog(@"app位於後臺通知(didReceiveRemoteNotification:fetchCompletionHandler:):%@", userInfo);
}
}
completionHandler(UIBackgroundFetchResultNewData);
}
#pragma mark - iOS>=10 中收到推送訊息
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
// iOS>=10: App在前臺獲取到通知
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler
API_AVAILABLE(ios(10.0)) {
NSDictionary * userInfo = notification.request.content.userInfo;
if (userInfo) {
NSLog(@"app位於前臺通知(willPresentNotification:):%@", userInfo);
}
completionHandler(UNNotificationPresentationOptionBadge|UNNotificationPresentationOptionSound|UNNotificationPresentationOptionAlert);;
}
// iO>=10: 點選通知進入App時觸發(殺死/切到後臺喚起)
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler
API_AVAILABLE(ios(10.0)) {
NSDictionary * userInfo = response.notification.request.content.userInfo;
if (userInfo) {
NSLog(@"點選通知進入App時觸發(didReceiveNotificationResponse:):%@", userInfo);
}
completionHandler();
}
#endif
@end
- 模擬推送工具“Pusher”
本文只側重於介紹iOS端對遠端推送通知的處理,因此我們把App Server
對應的處理過程交給了第三方工具,第三方推送測試工具有很多,如SmartPush、Pusher等,在這裡我們選用Pusher作為測試工具,Pusher的GitHub地址。
Pusher的使用步驟說明:
(1)選擇p12
格式的推送證照;
(2)設定是否為測試環境(預設勾選為測試環境,由於推送證照分為測試推送證照和生產測試證照,並且蘋果的APNs
也分為測試和生產兩套環境,因此Pusher
需要手動置頂是否為測試環境);
(3)輸入device token
;
(4)輸入符合蘋果要求的推送內容字串;
(5)當確認手機端設定無誤,並且以上4點設定正確時,執行推送。
Pusher推送的訊息,以第4點中的示例為例進行測試,手機收到遠端推送通知的效果截圖如下:
點選遠端推送通知橫幅開啟App,在回撥中獲取的
json
串:備註:
(1)要使用APNs
向非執行的應用程式提供遠端通知,需要至少啟動目標應用程式一次;
(2)裝置沒有網路的情況下,是無法註冊遠端通知的;
(3)一般情況下,device token
是不會發生變化的,即雖然呼叫註冊遠端通知的方法,但是返回的device token
仍然是之前得到的值;如果裝置令牌在應用程式執行時發生更改,則應用程式物件再次呼叫相應的委託方法以通知更改;
(4)推送過程中的訊息json
串可在適當位置新增自定義欄位,整個訊息最大長度為4 KB
(4096
位元組),超過最大允許長度,則拒絕通知;
(5)在iOS及以上系統中遠端通知還包括“通知擴充套件”功能,在下一篇文章中介紹。
本文Demo連結:GitHub地址
專欄下一篇:iOS 通知擴充套件
關注我們的途徑有:
QiShare(簡書)
QiShare(掘金)
QiShare(知乎)
QiShare(GitHub)
QiShare(CocoaChina)
QiShare(StackOverflow)
QiShare(微信公眾號)
相關文章
- iOS推送之遠端推送iOS
- iOS開發之遠端推送iOS
- iOS 通知中心(NSNotificationCenter)iOS
- android收款語音播報+個推遠端通知、透傳推送Android
- iOS遠端hot patch的優點和風險iOS
- iOS列印日誌到遠端伺服器iOS伺服器
- iOS 通知擴充套件iOS套件
- nagios mail告警通知iOSAI
- iOS本地通知(推送)iOS
- iOS ANCS 通知服務iOS
- iOS 本地通知NSNotificationcenter --- iOS 開發iOS
- 【iOS逆向與安全】iOS遠端大師:透過H5後臺遠端檢視和協助iPhone裝置iOSH5iPhone
- iOS下 建立遠端cocoapods私有庫的套路iOS
- iOS開發: 配置CocoaPods遠端私有倉庫iOS
- iOS開發-鍵盤通知iOS
- iOS中通知非同步?同步?iOS非同步
- iOS 本地通知那些事iOS
- iOS 12 通知新特性 —— 自定義 App 通知的外觀iOSAPP
- iOS APNS推送遠端訊息 java後臺實現iOSJava
- 遠端連線桌面 批次遠端管理
- 微軟認證:遠端開啟遠端計算機的遠端桌面微軟計算機
- iOS 通知擴充套件外掛iOS套件
- iOS 通知還能這麼玩?iOS
- iOS10推送通知適配iOS
- iOS 本地通知(未完待續)iOS
- ios推送:本地通知UILocalNotificationiOSUI
- 關於fastjson出現反序列化遠端程式碼執行漏洞的通知ASTJSON
- 遠端桌面連線命令 批次遠端管理
- 批次遠端桌面連線 批次遠端桌面
- iOS學習筆記07 運動事件和遠端控制iOS筆記事件
- iOS 播放遠端網路音樂的核心技術點iOS
- iOS 元件化開發(一):遠端私有庫的基本使用iOS元件化
- iOS推送——本地推送與遠端推送詳解(一圖看懂)iOS
- 遠端推送
- 遠端桌面
- vnc遠端用外網遠端公司內網,3步實現vnc遠端用外網遠端公司內網VNC內網
- Cisco Secure Client 5.1.6.103 (macOS, Linux, Windows & iOS, Andrord) - 遠端訪問客戶端clientMacLinuxWindowsiOS客戶端
- 批次遠端桌面管理軟體 批次遠端桌面