iOS 消息推送

[TOC]

一、工作机制:

APNS 是 Apple Push Notification Service 的缩写,是苹果服务器。

image

工作流程如下所示:

  • 首先app向iOS注册推送消息
  • iOS收到app的注册后,向APNS Server索要deviceToken,app接收返回的deviceToken
  • app把接收到的deviceToken传给我们的服务器
  • 当我们的服务器需要推送消息时,就把要推送的消息和deviceToken发送给APNS Server
  • APNS Server服务将推送的消息发送给app

二、app代码实现:

1、注册消息推送:

#import 

// 注册APNS推送
- (void)registerRemoteNotification {
    if (@available(iOS 10.0, *)) {
        UNUserNotificationCenter *notificationCenter = [UNUserNotificationCenter currentNotificationCenter];
        // 必须写代理,不然无法监听通知的接收与点击事件
        notificationCenter.delegate = self;
        // 请求授权
        [notificationCenter requestAuthorizationWithOptions:UNAuthorizationOptionAlert
                                          completionHandler:^(BOOL granted, NSError * _Nullable error) {
                                              if (granted && !error) {
                                                  // 用户同意授权,注册远程推送
                                                  [[UIApplication sharedApplication] registerForRemoteNotifications];
                                              } else {
                                                  // 用户不同意授权
                                              }
                                          }];
        // 获取用户同意的或者更改的推送权限设置
        [notificationCenter getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
            NSLog(@"%@",settings);
        }];
        
    } else {
        // iOS8 ~ iOS10
        if ([[UIApplication sharedApplication] respondsToSelector:@selector(registerUserNotificationSettings:)]) {
            UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert categories:nil];
            [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
            
        } else {
            [[UIApplication sharedApplication] registerForRemoteNotificationTypes:UIRemoteNotificationTypeAlert];
        }
    }
}

2、把拿到到deviceToken传给我们的服务器:

// 获取deviceToken成功
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    
    // 把deviceToken转为NSString
    NSString *deviceStr = [[deviceToken description] stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]];
    deviceStr = [deviceStr stringByReplacingOccurrencesOfString:@" " withString:@""];
    
    // 把deviceToken传给我们自己的服务器
    
}

// 获取deviceToken失败
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
    NSLog(@"error:%@",error.description);
}

3、app接收到远程推送的消息:

#pragma mark iOS10 收到通知(本地和远程)

// App接收通知时
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
       willPresentNotification:(UNNotification *)notification
         withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler  API_AVAILABLE(ios(10.0)){
    // 收到推送的请求
    UNNotificationRequest *request = notification.request;
    // 收到推送的内容
    UNNotificationContent *content = request.content;
    // 收到推送的基本信息
    NSDictionary *userInfo = content.userInfo;
    // 收到推送消息的角标
    NSNumber *badge = content.badge;
    // 推送消息的声音
    UNNotificationSound *sound = content.sound;
    // 推送消息的副标题
    NSString *subtitle = content.subtitle;
    // 推送消息的标题
    NSString *title = content.title;
    // 推送消息的类型
    if ([request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
        // 远程通知
    } else if ([request.trigger isKindOfClass:[UNTimeIntervalNotificationTrigger class]]) {
        // 本地通知,一定时间之后,重复或者不重复推送通知 我们可以设置timeInterval(时间间隔)和repeats(是否重复)。
    } else if ([request.trigger isKindOfClass:[UNCalendarNotificationTrigger class]]) {
        // 本地通知,一定日期之后,重复或者不重复推送通知 例如,你每天8点推送一个通知,只要dateComponents为8,如果你想每天8点都推送这个通知,只要repeats为YES就可以了
    } else if ([request.trigger isKindOfClass:[UNLocationNotificationTrigger class]]) {
        // 本地通知,地理位置的一种通知,当用户进入或离开一个地理区域来通知。
    }
    
    // 执行下面方法,选择提醒用户的方式
    completionHandler(UNNotificationPresentationOptionBadge|
                      UNNotificationPresentationOptionSound|
                      UNNotificationPresentationOptionAlert);
}

// App通知的点击事件,只会是用户点击消息才会触发,如果使用户长按(3DTouch)、Action等并不会触发。
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
         withCompletionHandler:(void (^)(void))completionHandler  API_AVAILABLE(ios(10.0)){
    // 收到推送的请求
    UNNotificationRequest *request = response.notification.request;
    
    // 。。。
    
    // 系统要求执行这个方法
    completionHandler();
}



#pragma mark iOS10 之前收到通知

// iOS10以下收到本地推送通知
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
    
}

// iOS7及以上收到通知
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
    
    completionHandler(UIBackgroundFetchResultNewData);
}

// iOS6及以下收到通知
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
    
}

三、本地推送:

本地推送这里主要分两个版本来介绍,一个是iOS 10及以后,一个是iOS 10以前;

1、iOS 10及以上本地推送生成流程:

  • 创建一个触发器 trigger

  • 创建推送的内容 UNMutableNotificationContent

  • 创建推送请求 UNNotificationRequest

  • 推送请求添加到推送管理中心 UNUserNotificationCenter

    - (void)postLocalNotificatonUpper10 API_AVAILABLE(ios(10.0)) {
        
        // 1. 创建一个触发器(trigger),这里以 UNTimeIntervalNotificationTrigger 为例
        UNTimeIntervalNotificationTrigger *timeTrigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:30 repeats:NO];
        
        // 2. 创建推送的内容 UNMutableNotificationContent
        UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
        content.title = @"title";
        content.subtitle = @"subtitle";
        content.body = @"body";
        content.badge = @2;
        content.sound = [UNNotificationSound defaultSound];
        content.userInfo = @{@"key1" : @"value1", @"key2" : @"value2"};
        
    //    // 推送交互操作
    //    content.categoryIdentifier = @"Dely_locationCategory";
    //    [self addNotificationAction];
    
        // 3. 创建推送请求 UNNotificationRequest
        UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:@"identifier"
                                                                              content:content
                                                                              trigger:timeTrigger];
        
        // 4. 推送请求添加到推送管理中心 UNUserNotificationCenter
        UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
        [center addNotificationRequest:request
                 withCompletionHandler:^(NSError * _Nullable error) {
                     if (!error) {
                         NSLog(@"推送已添加成功");
                     }
                 }];
    }
    

2、iOS 10以下本地推送生成流程:

  • 创建本地通知对象 UILocalNotification
  • 把本地通知对象加入到app日程表中
- (void)postLocalNotificatonBelow10 {
    /*
     fireDate:启动时间
     timeZone:启动时间参考的时区
     repeatInterval:重复推送时间(NSCalendarUnit类型),0代表不重复
     repeatCalendar:重复推送时间(NSCalendar类型)
     alertBody:通知内容
     alertAction:解锁滑动时的事件
     alertLaunchImage:启动图片,设置此字段点击通知时会显示该图片
     alertTitle:通知标题,适用iOS8.2之后
     applicationIconBadgeNumber:收到通知时App icon的角标
     soundName:推送是带的声音提醒,设置默认的字段为UILocalNotificationDefaultSoundName
     userInfo:发送通知时附加的内容
     category:此属性和注册通知类型时有关联,(有兴趣的同学自己了解,不详细叙述)适用iOS8.0之后
     
     region:带有定位的推送相关属性,具体使用见下面【带有定位的本地推送】适用iOS8.0之后
     regionTriggersOnce:带有定位的推送相关属性,具体使用见下面【带有定位的本地推送】适用iOS8.0之后
     */
    
    // 1. 创建本地通知对象 UILocalNotification
    UILocalNotification *localNotification = [[UILocalNotification alloc] init];
    localNotification.fireDate = [NSDate dateWithTimeIntervalSinceNow:30];
    localNotification.alertBody = @"通知显示内容";
    localNotification.alertAction = @"解锁滑动是的事件";
    localNotification.applicationIconBadgeNumber = 1;
    localNotification.soundName = UILocalNotificationDefaultSoundName;
    
    // 2. 把本地通知对象加入到app日程表中
    [[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
    
    // 立即发送通知
//    [[UIApplication sharedApplication] presentLocalNotificationNow:localNotification];
    
}

四、iOS 10推送交互操作:

iOS 10中,可以允许推送添加交互操作 action,这些 action 使得app可以在前台或者后台执行一些逻辑代码。这是推送功能的一个拓展,可通过3D-Touch触发,或者右滑会出现view和clear选项来触发。

  • 创建action
  • 创建category
  • 把category添加到通知中心
// 添加推送交互操作
- (void)addNotificationAction API_AVAILABLE(ios(10.0)) {
    /*
     1.需要解锁显示,点击不会进app
     UNNotificationActionOptionAuthenticationRequired
     2.点击不会进app
     UNNotificationActionOptionDestructive
     3.点击会进app
     UNNotificationActionOptionForeground
     */
    // 1. 创建action
    UNNotificationAction *lookAction =
    [UNNotificationAction actionWithIdentifier:@"action.join"
                                         title:@"接收邀请"
                                       options:UNNotificationActionOptionAuthenticationRequired];
    UNNotificationAction *joinAction =
    [UNNotificationAction actionWithIdentifier:@"action.look"
                                         title:@"查看邀请"
                                       options:UNNotificationActionOptionForeground];
    UNNotificationAction *cancelAction =
    [UNNotificationAction actionWithIdentifier:@"action.cancel"
                                         title:@"取消"
                                       options:UNNotificationActionOptionDestructive];
    
    // 2. 创建category
    // * identifier 标识符
    // * actions 操作数组
    // * intentIdentifiers 意图标识符 可在  中查看,主要是针对电话、carplay 等开放的 API。
    // * options 通知选项 枚举类型 也是为了支持 carplay
    UNNotificationCategory *category =
    [UNNotificationCategory categoryWithIdentifier:@"Dely_locationCategory"
                                           actions:@[lookAction, joinAction, cancelAction]
                                 intentIdentifiers:@[]
                                           options:UNNotificationCategoryOptionCustomDismissAction];
    
    // 3. 把category添加到通知中心
    [[UNUserNotificationCenter currentNotificationCenter] setNotificationCategories:[NSSet setWithObject:category]];
    
}

// 添加推送文本输入交互操作
- (void)addTextNotificationAction API_AVAILABLE(ios(10.0)) {
    // 创建 UNTextInputNotificationAction 比 UNNotificationAction 多了两个参数
    // * buttonTitle 输入框右边的按钮标题
    // * placeholder 输入框占位符
    UNTextInputNotificationAction *inputAction =
    [UNTextInputNotificationAction actionWithIdentifier:@"action.input"
                                                  title:@"输入"
                                                options:UNNotificationActionOptionForeground
                                   textInputButtonTitle:@"发送"
                                   textInputPlaceholder:@"tell me loudly"];
    
    // 注册 category
    UNNotificationCategory *notificationCategory =
    [UNNotificationCategory categoryWithIdentifier:@"Dely_locationCategory"
                                           actions:@[inputAction]
                                 intentIdentifiers:@[]
                                           options:UNNotificationCategoryOptionCustomDismissAction];
    
    [[UNUserNotificationCenter currentNotificationCenter] setNotificationCategories:[NSSet setWithObject:notificationCategory]];
}
  • 事件的操作
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
         withCompletionHandler:(void (^)(void))completionHandler  API_AVAILABLE(ios(10.0)){
    // iOS 10推送交互事件的操作,在这里处理
    //点击或输入action
    NSString* actionIdentifierStr = response.actionIdentifier;
    
    //输入
    if ([response isKindOfClass:[UNTextInputNotificationResponse class]]) {
        NSString* userSayStr = [(UNTextInputNotificationResponse *)response userText];
    }
    
    //点击
    if ([actionIdentifierStr isEqualToString:@"action.join"]) {
    } else if ([actionIdentifierStr isEqualToString:@"action.look"]) {
    }
    
    
    // 系统要求执行这个方法
    completionHandler();
}

注意,远程推送一定要保证 category 的键值对是一致的

{
  "aps" : {
    "alert" : {
      "title" : "iOS远程消息,我是主标题!-title",
      "subtitle" : "iOS远程消息,我是主标题!-Subtitle",
      "body" : "Dely,why am i so handsome -body"
    },
    "category" : "Dely_locationCategory",
    "badge" : "2"
  }
}

五、Reference

iOS开发,本地推送的使用

iOS 10 消息推送(UserNotifications)秘籍总结(一)

iOS 10 消息推送(UserNotifications)秘籍总结(二)

你可能感兴趣的:(iOS 消息推送)