iOS推送通知相关
iOS 开发中主要有三种推送通知:
用户通知 (User Notifications): 这是最常见的类型,用于向用户显示可见的提醒。用户通知可以包含文本、图标、声音和自定义操作按钮。用户需要授权应用才能发送用户通知。
本地通知 (Local Notifications): 由应用程序本身在设备上调度和触发。
远程通知 (Remote Notifications/Push Notifications): 由您的服务器通过 Apple 推送通知服务 (APNs) 发送到用户的设备。
后台推送通知 (Background Push Notifications/Silent Notifications): 这些通知不会显示给用户,而是在后台唤醒应用程序以执行一些操作,例如更新内容或同步数据。 它们在 iOS 7 中引入,旨在提高应用程序的效率和用户体验。 虽然用户看不到这些通知,但它们对于保持应用程序数据最新至关重要。
数据结构:
推送通知的数据结构是 JSON 格式的 Payload(有效负载)。 虽然您可以自定义 Payload 中的数据,但某些键对于 APNs 来说是必需的,并且必须遵循 Apple 定义的格式才能使通知正常工作。
一个典型的远程通知 Payload 示例:
{
"aps": {
"alert": {
"title": "通知标题",
"subtitle": "通知副标题",
"body": "通知内容"
},
"badge": 1,
"sound": "default",
"category": "myCategory"
},
"customKey": "customValue"
}
aps:这是必需的键,包含 Apple 定义的标准字段。
alert:定义通知的文本内容。
badge:应用程序图标上的角标数字。
sound:通知的声音。
category:用于定义自定义操作按钮。
customKey:您可以添加自定义键值对来传递特定于应用程序的数据。
区别:
主要区别在于用户是否可见以及如何处理通知。 用户通知会立即提醒用户,而后台推送通知则在后台静默处理。 不同的通知类型使用 Payload 中不同的键来控制其行为。 例如,content-available 键用于后台推送通知。
不按苹果规定的结构推送数据:
如果您不遵循 Apple 定义的 Payload 结构,APNs 可能无法正确解析通知,导致通知无法送达或无法按预期工作。 例如,静默推送需要在 aps 字典中包含 "content-available": 1 键值对。 如果缺少此键值对,系统会将通知视为常规远程通知,可能会显示给用户,而不是在后台静默处理。
后台推送通知不会直接显示给用户,而是在后台唤醒应用程序以执行一些操作,例如更新内容或同步数据。
{
"aps": {
"content-available": 1 // 必须设置为 1 以指示静默推送
},
"data": {
"updateType": "new_messages",
"count": 3
}
}
iOS注册推送
#import "AppDelegate.h"
#import <UserNotifications/UserNotifications.h>
@interface AppDelegate () <UNUserNotificationCenterDelegate>
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// 请求推送权限
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
[center requestAuthorizationWithOptions:(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge)
completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (!error) {
// 注册远程推送
dispatch_async(dispatch_get_main_queue(), ^{
[application registerForRemoteNotifications];
});
}
}];
return YES;
}
// 获取Device Token
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
// 将 deviceToken 发送到后端服务器
NSString *tokenString = [[[[deviceToken description]
stringByReplacingOccurrencesOfString: @"<" withString: @""]
stringByReplacingOccurrencesOfString: @">" withString: @""]
stringByReplacingOccurrencesOfString: @" " withString: @""];
NSLog(@"Device Token: %@", tokenString);
}
// 推送注册失败
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
NSLog(@"Failed to register for remote notifications: %@", error);
}
// 处理接收到的推送消息 (iOS 10+)
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler API_AVAILABLE(ios(10.0)){
// 应用在前台时收到推送的处理
NSLog(@"Received notification in foreground: %@", notification.request.content.userInfo);
completionHandler(UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionSound | UNNotificationPresentationOptionBadge);
}
// 用户点击推送消息后的回调 (iOS 10+)
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)(void))completionHandler API_AVAILABLE(ios(10.0)){
// 应用在后台或关闭状态时,用户点击推送后的处理
NSLog(@"User tapped on notification: %@", response.notification.request.content.userInfo);
completionHandler();
}
// 处理接收到的推送消息 (iOS 10 以下)
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
NSLog(@"Received notification: %@", userInfo);
}
@end
iOS 推送需要后端配合完成以下步骤:
-
需要从 Apple Developer 网站创建并下载推送证书(.p12 文件)。此证书用于对与 APNs 的连接进行身份验证。
后端需要妥善保管此证书文件,并将其配置在服务器上,用于与 APNs 通信。
与 APNs 通信: -
后端服务器需要使用推送证书与 Apple 推送通知服务 (APNs) 建立连接。
使用 HTTP/2 协议与 APNs 的 api.push.apple.com (生产环境) 或 api.development.push.apple.com (开发环境) 进行通信。
构建推送消息: -
后端需要根据 APNs 规范构建 JSON 格式的推送消息,其中包含目标设备的 device token,消息内容,以及其他自定义数据等。
发送推送消息: -
后端将构建好的 JSON 推送消息通过 HTTP/2 POST 请求发送到 APNs。
APNs 会将消息推送至目标 iOS 设备。
处理推送反馈:
APNs 会向后端服务器发送反馈信息,告知哪些设备的 device token 不再有效。后端需要根据反馈信息更新 device token 列表,避免向无效的 device token 发送推送消息,从而节省资源和提高效率。
#import <Foundation/Foundation.h>
#import <UserNotifications/UserNotifications.h>
NS_ASSUME_NONNULL_BEGIN
@protocol PushNotificationDelegate <NSObject>
@required
- (void)didReceiveLocalNotification:(UNNotification *)notification;
- (void)didReceiveRemoteNotification:(UNNotification *)notification;
@end
@interface PushNotificationSDK : NSObject
@property (nonatomic, weak) id<PushNotificationDelegate> delegate;
+ (instancetype)sharedInstance;
- (void)registerForPushNotifications;
- (void)handleRemoteNotification:(NSDictionary *)userInfo;
- (void)handleLocalNotification:(NSDictionary *)userInfo;
@end
NS_ASSUME_NONNULL_END
#import "PushNotificationSDK.h"
#import <UserNotifications/UserNotifications.h>
@implementation PushNotificationSDK
+ (instancetype)sharedInstance {
static PushNotificationSDK *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
- (void)registerForPushNotifications {
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
[center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert + UNAuthorizationOptionSound + UNAuthorizationOptionBadge)
completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (granted) {
dispatch_async(dispatch_get_main_queue(), ^{
[[UIApplication sharedApplication] registerForRemoteNotifications];
});
}
}];
}
- (void)handleRemoteNotification:(NSDictionary *)userInfo {
UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
content.title = userInfo[@"title"];
content.body = userInfo[@"body"];
content.sound = [UNNotificationSound defaultSound];
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:@"RemoteNotification" content:content trigger:nil];
[[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request withCompletionHandler:nil];
UNNotification *notification = [[UNNotification alloc] init];
[self.delegate didReceiveRemoteNotification:notification];
}
- (void)handleLocalNotification:(NSDictionary *)userInfo {
UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
content.title = userInfo[@"title"];
content.body = userInfo[@"body"];
content.sound = [UNNotificationSound defaultSound];
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:@"LocalNotification" content:content trigger:nil];
[[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request withCompletionHandler:nil];
UNNotification *notification = [[UNNotification alloc] init];
[self.delegate didReceiveLocalNotification:notification];
}
#pragma mark - UNUserNotificationCenterDelegate
// App在前台时收到通知处理
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler {
if ([notification.request.identifier isEqualToString:@"RemoteNotification"]) {
[self.delegate didReceiveRemoteNotification:notification];
} else if ([notification.request.identifier isEqualToString:@"LocalNotification"]) {
[self.delegate didReceiveLocalNotification:notification];
}
completionHandler(UNNotificationPresentationOptionAlert + UNNotificationPresentationOptionSound);
}
// 点击通知时触发
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler {
if ([response.notification.request.identifier isEqualToString:@"RemoteNotification"]) {
[self.delegate didReceiveRemoteNotification:response.notification];
} else if ([response.notification.request.identifier isEqualToString:@"LocalNotification"]) {
[self.delegate didReceiveLocalNotification:response.notification];
}
completionHandler();
}
@end
#import "AppDelegate.h"
#import "PushNotificationSDK.h"
@interface AppDelegate () <PushNotificationDelegate>
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// 注册推送通知
[[PushNotificationSDK sharedInstance] registerForPushNotifications];
[PushNotificationSDK sharedInstance].delegate = self;
return YES;
}
// 实现PushNotificationDelegate协议方法
- (void)didReceiveLocalNotification:(UNNotification *)notification {
// 自定义UI处理本地通知
NSLog(@"Received Local Notification: %@", notification.request.content.body);
// 在这里自定义UI处理
}
- (void)didReceiveRemoteNotification:(UNNotification *)notification {
// 自定义UI处理远程通知
NSLog(@"Received Remote Notification: %@", notification.request.content.body);
// 在这里自定义UI处理
}
// 处理远程通知
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
[[PushNotificationSDK sharedInstance] handleRemoteNotification:userInfo];
}
// 获取设备的推送通知令牌
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
const unsigned *tokenBytes = [deviceToken bytes];
NSString *hexToken = [NSString stringWithFormat:@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
tokenBytes[0], tokenBytes[1], tokenBytes[2], tokenBytes[3],
tokenBytes[4], tokenBytes[5], tokenBytes[6], tokenBytes[7],
tokenBytes[8], tokenBytes[9], tokenBytes[10], tokenBytes[11],
tokenBytes[12], tokenBytes[13], tokenBytes[14], tokenBytes[15]];
NSLog(@"Device Token: %@", hexToken);
// 你可以在这里将deviceToken发送到你的服务器
}
@end
本文来自博客园,作者:CoderWGB,转载请注明原文链接:https://www.cnblogs.com/wgb1234/articles/18679994

浙公网安备 33010602011771号