本篇文章对APNS推送进行几点总结:
- 1.ANPS 原理是什么?
- 2.工程如何集成APNS推送
- 3.项目中遇到的坑
一.ANPS 原理
1.
App
在代码中注册消息推送弹框 ;
2.iOS从ANPS
服务器获取Device Token
,回传给APP
;
3.APP
将Device Token
发送给自己公司服务器
;
4.APP
发消息到自己公司服务器
后,自己公司服务器
将要发送的消息,目的iPhone的标识打包发送给ANPS
服务器;
5.ANPS
服务器在自身的已注册Push服务的设备列表中,查找有相应标识的设备,并把消息发送到设备的APP
,并且按照设定弹出Push通知。
具体原理图看下图解释:
二.集成APNS推送过程
1.创建推送证书
从钥匙串中创建CRS文件,具体操作步骤见下图:
2.创建推送证书
登录开发者网站->登录账号->创建push推送证书(Development+Distribute)->下载证书->从钥匙串中导出P12证书-发送给公司服务器
3.创建代码
注册APNS推送请求
在- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
方法中添加如下代码:
//APNS推送
if (kDeviceSystemVersion >= 10.0) {
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
UNAuthorizationOptions type = UNAuthorizationOptionAlert|UNAuthorizationOptionBadge|UNAuthorizationOptionSound;
[center requestAuthorizationWithOptions:type completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (granted) {
NSLog(@"注册APNS成功");
dispatch_async(dispatch_get_main_queue(), ^{
[[UIApplication sharedApplication] registerForRemoteNotifications];
});
} else {
NSLog(@"注册APNS失败");
}
}];
} else if(kDeviceSystemVersion >= 8.0){
UIUserNotificationType type = UIUserNotificationTypeAlert|UIUserNotificationTypeSound|UIUserNotificationTypeBadge;
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:type categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
} else {
UIRemoteNotificationType type = UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge|UIRemoteNotificationTypeSound;
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:type];
}
程序第一次安装的请求弹框如下图:
点击允许后应用接收device token
注册device token成功,调用如下代码:
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
//iOS13 后
NSMutableString *tokenString = [NSMutableString string];
const char *bytes = deviceToken.bytes;
int iCount = deviceToken.length;
for (int i = 0; i < iCount; i++) {
[tokenString appendFormat:@"%02x", bytes[i]&0x000000FF];
}
NSLog(@"tokenString = %@", tokenString);
[[NSUserDefaults standardUserDefaults] setObject:tokenString forKey:@"DeviceTokenString"];
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"autoRemotePush"];
if (![[NSUserDefaults standardUserDefaults] boolForKey:@"pushToken"] && [[NSUserDefaults standardUserDefaults] objectForKey:@"DeviceTokenString"]) {
[self pushToken:tokenString];
}
}
注册device token失败,调用如下代码
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
NSLog(@"did Fail To Register For Remote Notifications With Error: %@", error);
}
将devicetoken 推送给自己公司服务器,推送代码自行编写
4.接收push消息
iOS10以上的通知用UNUserNotificationDelegate接收通知
程序退到后台接收push推送
//ios10之后 应用在后台接收推送消息
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)(void))completionHandler {
NSLog(@"%s", __func__);
NSDictionary * userInfo = response.notification.request.content.userInfo;
NSDictionary *apsDic = [userInfo objectForKey:@"aps"];
UIApplication *application = [UIApplication sharedApplication];
if([response.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
[self receivedNotification:userInfo application:application];
}
else {
// 判断为本地通知
}
// Warning: UNUserNotificationCenter delegate received call to
completionHandler(); // 系统要求执行这个方法
}
iOS10应用在前台收到push 消息
//ios10 应用在前台是否接收推送消息
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler API_AVAILABLE(ios(10.0)){
NSLog(@"%s", __func__);
NSDictionary * userInfo = notification.request.content.userInfo;
NSDictionary *apsDic = [userInfo objectForKey:@"aps"];
UIApplication *application = [UIApplication sharedApplication];
if([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
[self receivedNotification:userInfo application:application];
}
else {
// 判断为本地通知
}
}
iOS10 以下系统收到push 消息
//ios3-ios10 收到推送消息
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
[self receivedNotification:userInfo application:application];
}
//ios7 点击推送消息进入
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
[self receivedNotification:userInfo application:application];
completionHandler(UIBackgroundFetchResultNewData);
}
5.程序被杀死,点击通知栏的push消息
if ([[launchOptions allKeys] containsObject:UIApplicationLaunchOptionsRemoteNotificationKey]) {//用户是点击通知栏推送启动的
NSDictionary *remoteNotification = [launchOptions objectForKey: UIApplicationLaunchOptionsRemoteNotificationKey];
// NSDictionary *apsDic = [remoteNotification objectForKey:@"aps"];
// NSString *message = [apsDic objectForKey:@"alert"];
// NSString *badge = [apsDic objectForKey:@"badge"];//红点数量
// NSString *sound = [apsDic objectForKey:@"sound"];//声音
[self receivedNotification:remoteNotification application:application];
NSUserDefaults *notificationDic = [NSUserDefaults standardUserDefaults];
[notificationDic setObject:remoteNotification forKey:@"notification"];
}else{
NSLog(@"用户是正常启动的程序");
}
6.处理推送消息,代码自行编写
三 注意说明
-
- icon角标数字变化
应用图标的applicationIconBadgeNumber变化由 推送消息中的badge决定,接收消息的声音由 推送消息的sound 决定。
- 2.点击弹框允许后不走
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
方法
a.推送证书是否有效
b.项目的Push Notifications
是否开启
- 3.同样的系统,同样的代码,同样的证书,有的手机能收到devicetoken,正常注册APNS推送,有的手机就不能收到devicetoken
极有可能是设备问题,我就遇到了同样的问题,然后用同事手机测试的。
本篇先记录到此,感谢阅读,如有错误,不吝赐教!