iOS APNs推送机制
2020-08-14 本文已影响0人
Cherry_06
APNs简介
Apple Push Notification service(APNs),即苹果推送通知服务。注:这里指的是远程推送通知,不包括本地通知。
为什么会有APNs
移动设备内存、CPU、电量的局限性,iOS不允许app的进程常驻后台(申请特殊权限除外)。
当用户主动杀掉app或者app进入后台超过限定时长时,就意味着app进程的结束。这很大程序保障了前台app的流畅性,也处长了手机的使用时长,这也是苹果用户体验好的原因之一。但也意味着服务器无法主动和用户交互了,比如推送实时消息。为了解决这个限制,苹果推出了APNs,允许设备和服务器分别与苹果的推送通知服务器保持长连接状态。
准备工作
在苹果后台给对应的App ID开通Push Notifications权限,生成profile(用于真机测试),生成APNs证书(用于服务端),
推送流程
iOS代码
注册推送:
首先引入UserNotifications.framework,引入头文件
#import <UserNotifications/UserNotifications.h>
- 在didFinishLaunchingWithOptions方法中注册通知:
if (@available(iOS 10.0, *)) {
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];
});
} else {
NSLog(@"APNs注册失败");
}
}];
} else if (@available(iOS 8.0, *)) {
UIUserNotificationType types = UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert;
UIUserNotificationSettings *mySettings = [UIUserNotificationSettings settingsForTypes:types categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:mySettings];
//register for deviceToken
[[UIApplication sharedApplication] registerForRemoteNotifications];
}
- 获取deviceToken
一般来说会将获取到的deviceToken发送给后台,用于指定设备发送通知。
//注册成功
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken{
NSString *deviceTokenStr = [[[[deviceToken description]
stringByReplacingOccurrencesOfString:@"<" withString:@""]
stringByReplacingOccurrencesOfString:@">" withString:@""]
stringByReplacingOccurrencesOfString:@" " withString:@""];
NSLog(@"deviceTokenStr:\n%@",deviceTokenStr);
}
//注册失败
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error{
NSLog(@"error -- %@",error);
}
注意
,如果注册失败,先检查证书是否配置正确,工程是否打开了push开关。另外,app只有在第一次安装时才会弹出系统权限提示。如果没有弹出,可以把app删除,重新build运行一次。
3.处理推送过来的消息
iOS10及以上:
//在前台是否展示
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler{
// 这个方法表明应用在前台也会通知声音、角标和提示
completionHandler(UNNotificationPresentationOptionBadge|
UNNotificationPresentationOptionSound|
UNNotificationPresentationOptionAlert);
}
//点击收到的消息,会触发下面方法,处理收到的数据
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler{
// [self handlePushMessage:response.notification.request.content.userInfo];
completionHandler();
}
iOS8以上iOS10以下:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary * _Nonnull)userInfo fetchCompletionHandler:(void (^ _Nonnull)(UIBackgroundFetchResult))completionHandler{
NSLog(@"didReceiveRemoteNotification:%@",userInfo);
/*
UIApplicationStateActive 应用程序处于前台
UIApplicationStateBackground 应用程序在后台,用户从通知中心点击消息将程序从后台 调至前台
UIApplicationStateInactive 用用程序处于关闭状态(不在前台也不在后台),用户通过点击通知中心的消息将客户端从关闭状态调至前台
*/
//应用程序在前台给一个提示特别消息
if (application.applicationState == UIApplicationStateActive) {
//应用程序在前台
[self createAlertViewControllerWithPushDict:userInfo];
}else{
//其他两种情况,一种在后台程序没有被杀死,另一种是在程序已经杀死。用户点击推送的消息进入app的情况处理。
[self handlePushMessage:userInfo];
}
completionHandler(UIBackgroundFetchResultNewData);
}
后台还未开发,或者收不到推送,如何测试iOS代码和证书有无问题?
我都是用Pusher这个软件,导入.p12证书,填入deviceToken就可以测试发送了。
后台的证书是.pem格式,可通过命令将.p12文件转为.pem文件:
openssl pkcs12 -in origin.p12 -out dis.pem -nodes