zoukankan      html  css  js  c++  java
  • iOS推送,看这篇足够了

    关于远程推送的相关配置网上已经有足够多的教程,这里就不复述了。这里讲述当客户端收到推送消息后,该怎样对其进行相应的逻辑处理。

    工程的AppDelegate.m文件里提供了如下方法:

    //当应用程序启动后,可能需要进行其他逻辑处理时调用的方法
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;
    
    //成功注册registerUserNotificationSettings:后,回调的方法
    - (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings;
     
    /// 注册失败调用
    - (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error;
    
    /// 用户同意接收通知后,会调用此程序
    - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken;
    
    //收到推送后调用的方法(iOS 10 及以上)
    - (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler;
     
    //收到推送后调用的方法(iOS 10 以下)
    - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler;
     
    //应用挂起前调用的方法(当有电话进来或者锁屏,应用会挂起)
    - (void)applicationWillResignActive:(UIApplication *)application;
     
    //当程序复原或启动时调用的方法
    - (void)applicationDidBecomeActive:(UIApplication *)application;
    
    //应用将要进入后台调用的方法
    - (void)applicationWillEnterForeground:(UIApplication *)application;
    
    //应用进入后台调用的方法
    -(void)applicationDidEnterBackground:(UIApplication *)application;
     
    //应用将要退出
    - (void)applicationWillTerminate:(UIApplication *)application;

    首先为应用程序注册通知:

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        NSDictionary *remoteNotification = [launchOptions objectForKey:@"UIApplicationLaunchOptionsRemoteNotificationKey"];
        if (remoteNotification != nil) {
            self.isLaunchedByNotification = YES;
        }else{
            self.isLaunchedByNotification = NO;
        }
        self.window=[[UIWindow alloc]initWithFrame:[[UIScreen mainScreen]bounds]];
        if ([[UIDevice currentDevice].systemVersion floatValue] >= 10.0) {
            UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
            center.delegate = self;
            [center requestAuthorizationWithOptions:(UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert) completionHandler:^(BOOL granted, NSError * _Nullable error) {
                if (!error) {
                    NSLog(@"succeeded!");
                }
            }];
        } else if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0){//iOS8-iOS9
            UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge | UIUserNotificationTypeAlert | UIUserNotificationTypeSound) categories:nil];
            [application registerUserNotificationSettings:settings];
            [application registerForRemoteNotifications];
        } else {//iOS8以下
            [application registerForRemoteNotificationTypes: UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound];
        }
        return YES;
    }

    用户同意后,会调用此程序,获取系统的deviceToken,应把deviceToken传给服务器保存,此函数会在程序每次启动时调用(前提是用户允许通知):

    - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
        NSLog(@"deviceToken = %@",deviceToken);
        NSString *token=[NSString stringWithFormat:@"%@",deviceToken];
        token=[token stringByReplacingOccurrencesOfString:@"<" withString:@""];
        token=[token stringByReplacingOccurrencesOfString:@">" withString:@""];
        token=[token stringByReplacingOccurrencesOfString:@" " withString:@""];
        //TODO
        //保存到本地并上传到服务器
    }

    收到推送消息后,进行相应的逻辑处理:

    //iOS 10 及以上
    - (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler {
        completionHandler(UIBackgroundFetchResultNewData);
        NSDictionary *userInfo = response.notification.request.content.userInfo;
        //程序关闭状态点击推送消息打开
        if (self.isLaunchedByNotification) {
            //TODO
        }
        else{
            //前台运行
            if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) {
                //TODO
            }
            //后台挂起时
            else{
                //TODO
            }
            //收到推送消息手机震动,播放音效
            AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
            AudioServicesPlaySystemSound(1007);
        }
        //设置应用程序角标数为0
        [UIApplication sharedApplication].applicationIconBadgeNumber = 9999;
        [UIApplication sharedApplication].applicationIconBadgeNumber = 0;
    }
    //iOS 10 以下
    - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
        completionHandler(UIBackgroundFetchResultNewData);    
        //程序关闭状态点击推送消息打开
        if (self.isLaunchedByNotification) {
            //TODO
        }
        else{
            //前台运行
            if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) {
                //TODO
            }
            //后台挂起时
            else{
                //TODO
            }
            //收到推送消息手机震动,播放音效
            AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
            AudioServicesPlaySystemSound(1007);
        }
        //设置应用程序角标数为0
        [UIApplication sharedApplication].applicationIconBadgeNumber = 9999;
        [UIApplication sharedApplication].applicationIconBadgeNumber = 0;
    }
    
    

    应用进入后台时,设置角标数(应用图标右上角小红点,未读消息数):

    -(void)applicationDidEnterBackground:(UIApplication *)application{
        [[UIApplication sharedApplication] setApplicationIconBadgeNumber:123];
    }
     

    实际应用:

    一、注册推送:

    - (void)registerNotification
    {
        if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 10.0)
        {
            if (@available(iOS 10.0, *)) {
                UNUserNotificationCenter * center =[UNUserNotificationCenter currentNotificationCenter];
                center.delegate=self;
                UNAuthorizationOptions options = UNAuthorizationOptionAlert|UNAuthorizationOptionSound|UNAuthorizationOptionBadge|UNAuthorizationOptionCarPlay;
                [center requestAuthorizationWithOptions:options completionHandler:^(BOOL granted, NSError * _Nullable error) {
                    if (granted) {
                    }else{
                        NSLog(@"授权失败");
                    }
                }];
            } else {
                // Fallback on earlier versions
            }
        }
        else if ([[[UIDevice currentDevice] systemVersion] floatValue]>=8.0)
        {
            UIUserNotificationSettings *sets= [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge|UIUserNotificationTypeAlert|UIUserNotificationTypeSound) categories:nil];
            [[UIApplication sharedApplication] registerUserNotificationSettings:sets];
        }
        else
        {
            UIRemoteNotificationType type = UIRemoteNotificationTypeAlert|UIRemoteNotificationTypeBadge|UIRemoteNotificationTypeSound;
            [[UIApplication sharedApplication] registerForRemoteNotificationTypes:type];
        }
            [[UIApplication sharedApplication] registerForRemoteNotifications];
    }

    假如用户第一次安装拒绝推送需要提醒的,按以下方法:(例子:iOS10 )

      UNUserNotificationCenter *userNotificationCenter = [UNUserNotificationCenter currentNotificationCenter];  
    
      userNotificationCenter.delegate = self;  
    
    //获取通知设置信息  
    
     [userNotificationCenter getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {  
    //用户还未做出选择  
    
      if (settings.authorizationStatus == UNAuthorizationStatusNotDetermined) {  
    
         //弹出授权框  
           [userNotificationCenter requestAuthorizationWithOptions:UNAuthorizationOptionAlert + UNAuthorizationOptionBadge + UNAuthorizationOptionSound completionHandler:^(BOOL granted, NSError * _Nullable error) {  
           if (granted) {  
    }
    else{               //首次授权为未授权状态,之后为已授权状态 DLog(@"没有开启通知"); } }]; }
      else if (settings.authorizationStatus == UNAuthorizationStatusDenied){     //用户不同意授权时,弹出提示(最好只弹一次)     UIAlertController *noticeNotificationAlertController = [UIAlertController alertControllerWithTitle:@"友情提示" message:@"建议您开启通知功能,以便及时获取相关信息" preferredStyle:UIAlertControllerStyleAlert]; [noticeNotificationAlertController addAction:[UIAlertAction actionWithTitle:@"忽略" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { }]]; [noticeNotificationAlertController addAction:[UIAlertAction actionWithTitle:@"去开启" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action){     NSURL *appSettingsUrl = [NSURL URLWithString:UIApplicationOpenSettingsURLString];     if ([[UIApplication sharedApplication] canOpenURL:appSettingsUrl]) { [[UIApplication sharedApplication] openURL:appSettingsUrl]; } }]]; [self.window.rootViewController presentViewController:noticeNotificationAlertController animated:YES completion:NULL]; }else{        //已授权 DLog(@"已授权通知"); }
    }];  

    二、本地推送:

    iOS10之后:

    //使用 UNNotification 本地通知  
    
    +(void)registerNotification:(NSInteger )alerTime{  
    
    // 使用 UNUserNotificationCenter 来管理通知  
    
        UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter];  
    
    //需创建一个包含待通知内容的 UNMutableNotificationContent 对象,注意不是 UNNotificationContent ,此对象为不可变对象。  
    
        UNMutableNotificationContent* content = [[UNMutableNotificationContent alloc] init];  
    
        content.title = [NSString localizedUserNotificationStringForKey:@"Hello!" arguments:nil];  
    
        content.body = [NSString localizedUserNotificationStringForKey:@"Hello_message_body"  arguments:nil];  
    
        content.sound = [UNNotificationSound defaultSound];  
    
    // 在 alertTime 后推送本地推送  
    
        UNTimeIntervalNotificationTrigger* trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:alerTime repeats:NO];  
    
        UNNotificationRequest* request = [UNNotificationRequest requestWithIdentifier:@"FiveSecond"  content:content trigger:trigger];  
    
    //添加推送成功后的处理!  
    
        [center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {  
    
         UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"本地通知" message:@"成功添加推送" preferredStyle:UIAlertControllerStyleAlert];  
    
         UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil];  
    
            [alert addAction:cancelAction];  
    
            [[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:alert animated:YES completion:nil];  
        }];  
    }  

    iOS10以前:

    + (void)registerLocalNotificationInOldWay:(NSInteger)alertTime {  
    
      UILocalNotification *notification = [[UILocalNotification alloc] init];  
    
      // 设置触发通知的时间  
    
      NSDate *fireDate = [NSDate dateWithTimeIntervalSinceNow:alertTime];  
    
        NSLog(@"fireDate=%@",fireDate);  
    
        notification.fireDate = fireDate;  
    
      // 时区  
    
        notification.timeZone = [NSTimeZone defaultTimeZone];  
    
      // 设置重复的间隔  
    
        notification.repeatInterval = kCFCalendarUnitSecond;  
    
      // 通知内容  
    
        notification.alertBody =  @"该起床了...";  
    
        notification.applicationIconBadgeNumber = 1;  
    
      // 通知被触发时播放的声音  
    
        notification.soundName = UILocalNotificationDefaultSoundName;  
    
      // 通知参数  
    
      NSDictionary *userDict = [NSDictionary dictionaryWithObject:@"开始学习iOS开发了" forKey:@"key"];  
    
        notification.userInfo = userDict;  
    
      // 通知重复提示的单位,可以是天、周、月  
    
         notification.repeatInterval = NSDayCalendarUnit;  
    
      // 将本地通知添加到调度池,定时发送
    
        [[UIApplication sharedApplication] scheduleLocalNotification:notification];  
    
       // 立即发送
    
        // [[UIApplication sharedApplication] presentLocalNotificationNow:localNotification];
    
    }  

    本地通知相关代理方法:

    // 当App在前台状态下,如果有通知会调用该方法

    // 当应用程序在后台状态下,点击推送通知,程序从后台进入前台后,会调用该方法(从锁屏界面点击推送通知从后台进入前台也会执行)

    // 当应用程序完全退出时不调用该方法

    - (void)application:(UIApplication *)application didReceiveLocalNotification:(nonnull UILocalNotification *)notification{
    
      NSLog(@"%@", notification);
    
      // 处理点击通知后对应的业务
    
      UIApplicationState applicationState = [[UIApplication sharedApplication] applicationState];
    
       if (applicationState == UIApplicationStateActive) {
    
      // 前台
    
      // 例如QQ会增加tabBar上的badgeValue未读数量
    
      }
    
      else if (applicationState == UIApplicationStateInactive) {
    
      // 从前台进入后台
    
      // 例如QQ会打开对应的聊天窗口
    
        NSInteger applicationIconBadgeNumber = application.applicationIconBadgeNumber - 1;
    
        application.applicationIconBadgeNumber = applicationIconBadgeNumber >= 0 ? applicationIconBadgeNumber : 0;
    
      }
    
       [application cancelLocalNotification:notification];
    
    }

    // 监听附加操作按钮

    - (void)application:(UIApplication *)application handleActionWithIdentifier:(nullable NSString *)identifier forLocalNotification:(nonnull UILocalNotification *)notification completionHandler:(nonnull void (^)())completionHandler {
    
      NSLog(@"identifier:%@", identifier); completionHandler();
    
    }

    // 该方法在iOS9.0后调用,iOS9.0之前调用上面那个方法

    - (void)application:(UIApplication *)app handleActionWithIdentifier:(nullable NSString *)identifier forLocalNotification:(nonnull UILocalNotification *)notification withResponseInfo:(nonnull NSDictionary *)responseInfo completionHandler:(nonnull void (^)())completionHandler {
    
      // ====identifier:no, content:{UIUserNotificationActionResponseTypedTextKey = "not agree";}
    
      NSLog(@"====identifier:%@, content:%@", identifier, responseInfo);
    
      completionHandler();
    
    }

    三、远程通知:

    1、什么是远程推送

    在联网的情况下,由远程服务器推送给客户端的通知,又称APNs(Apple Push Notification Services)不管应用是打开还是关闭的情况下,都能接收到服务器推送的远程通知在联网状态下,所有苹果设备都会与苹果服务器建立长连接

    2、远程推送的实现原理:

          1.打开App时: 发送UDIDBundleIDAPNs加密后返回deviceToken

          2.获取Token后,App调用接口,将用户身份信息和deviceToken发给服务器,服务器记录

          3.当推送消息时, 服务器按照用户身份信息找到存储的deviceToken,将消息和deviToken发送给APNs

          4.苹果的APNs通过deviceToken, 找到指定设备的指定程序, 并将消息推送给用户

    3、实现远程推送功能的前提

          1.真机

          2.调试阶段的证书

             iOS_development.cer 用于真机调试的证书

             aps_development.cer 用于真机推送调试能的证书

             xxx.mobileprovision 描述文件,记录了能够调试的手机、电脑和程序

          3.发布阶段的证书

              iOS_distribution.cer 用于发布app的证书

              aps.cer 用于发布时,让app有推送功能的证书

              xxx.mobileprovision 描述文件,记录了能够发布app的电脑

    如何配置证书, 不在本教程内, 请读者自行处理, 或者参考视频教程

    一、 注册远程推送并获取DeviceToken

    1.创建iOS的项目,并输入项目名字

    2.在AppDelegate中导入头文件:

    #import <UserNotifications/UserNotifications.h>

    3.在application:didFinishLaunchingWithOptions方法中, 注册远程通知

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    
     {
    
     //请求通知权限, 本地和远程共用
    
     UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
    
     [center requestAuthorizationWithOptions:UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert completionHandler:^(BOOLgranted, NSError * _Nullable error) {
    
      if(granted) {
    
       NSLog(@"请求成功");
    
        } else{
    
        NSLog(@"请求失败");
    
        }
    
       }];
    
     //注册远程通知
    
     [[UIApplication sharedApplication] registerForRemoteNotifications];
    
     //设置通知的代理
    
     center.delegate = self;
    
     returnYES;
    
     } 

    4.在接收远程推送的DeviceToken方法中, 获取Token

    - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
    
    {
    
    //将来需要将此Token上传给后台服务器
    
    NSLog(@"token:%@", deviceToken);
    
    }

    二、 iOS10之前通知的处理方法

    - (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
    
    {
    
      //此方法已被下面的方法代替
    
    }
    
    -(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
    
    {
    
       //iOS10之前,接收远程通知时,不管在前台、后台还是程序杀死都会调用此方法
    
       if (application.applicationState == UIApplicationStateActive) {
    
      // 前台收到通知处理
    
      }else{
    
      //后台或退出时点击通知处理
    
      }
    
          completionHandler();
    
    }

    三、 iOS10远程推送通知的处理方法

     当点击了推送后, 如果你希望进行处理. 那么在iOS10中, 还需要设置UNUserNotificationCenterdelegate, 并遵守UNUserNotificationCenterDelegate协议.

    以及实现下面实现3个方法, 用于处理点击通知时的不同情况的处理

           willPresentNotification:withCompletionHandler 用于前台运行

    didReceiveNotificationResponse:withCompletionHandler 用于后台及程序退出

    didReceiveRemoteNotification:fetchCompletionHandler用于静默推送

    //设置通知的代理

    center.delegate = self;

    1.前台运行 会调用的方法

    前台运行: 指的是程序正在运行中, 用户能看见程序的界面.

    iOS10会出现通知横幅, 而在以前的框架中, 前台运行时, 不会出现通知的横幅.

    - (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void(^)(UNNotificationPresentationOptions))completionHandler { NSDictionary *userInfo = notification.request.content.userInfo; //前台运行推送 显示红色Label [self showLabelWithUserInfo:userInfo color:[UIColor redColor]]; //可以设置当收到通知后, 有哪些效果呈现(声音/提醒/数字角标) completionHandler(UNNotificationPresentationOptionBadge | UNNotificationPresentationOptionSound | UNNotificationPresentationOptionAlert); }

    2.后台运行及程序退出 会调用的方法

    后台运行: 指的是程序已经打开, 用户看不见程序的界面, 如锁屏和按Home键.

    程序退出: 指的是程序没有运行, 或者通过双击Home键,关闭了程序.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    - (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)())completionHandler
     {
      NSDictionary *userInfo = response.notification.request.content.userInfo;
     
      //后台及退出推送 显示绿色Label
      [self showLabelWithUserInfo:userInfo color:[UIColor greenColor]];
     
      completionHandler();
     }

    3.静默推送通知 会调用的方法

    静默推送: iOS7以后出现, 不会出现提醒及声音.

    要求:

    推送的payload中不能包含alertsound字段

    需要添加content-available字段, 并设置值为1

    例如: {"aps":{"content-available":"1"},"PageKey”":"2"}

    1
    2
    3
    4
    5
    6
    7
    8
    //如果是以前的旧框架, 此方法 前台/后台/退出/静默推送都可以处理
    - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
    {
      //静默推送 显示蓝色Label
     [self showLabelWithUserInfo:userInfo color:[UIColor blueColor]];
     
     completionHandler(UIBackgroundFetchResultNewData);
     }

    4.处理通知的公用方法

    开发中, 点击通知的逻辑应当看自己程序的需求.

    这里为了方便演示, 简单的将通知的值, 通过UILabel显示在主界面上.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    - (void)showLabelWithUserInfo:(NSDictionary *)userInfo color:(UIColor *)color
    {
     UILabel *label = [UILabel new];
     label.backgroundColor = color;
     label.frame = CGRectMake(0, 250, [UIScreen mainScreen].bounds.size.width, 300);
     label.text = userInfo.description;
     label.numberOfLines = 0;
     [[UIApplication sharedApplication].keyWindow addSubview:label];
    }

     

    iOS10本地通知:http://www.jianshu.com/p/5713fa2bfece 

    对iOS的Push Notification的响应理解:https://www.jianshu.com/p/14bcec29f5c8

  • 相关阅读:
    android之PackageManager简单介绍
    西门子PLC学习笔记二-(工作记录)
    node.js第十课(HTTPserver)
    ubuntu ???????????? no permissions 问题解决
    Web API 设计摘要
    公共 DNS server IP 地址
    用Unicode迎接未来
    vs2010公布时去除msvcp100.dll和msvcr100.dll图讲解明
    linux串口驱动分析
    C++ 中dynamic_cast&lt;&gt;的用法
  • 原文地址:https://www.cnblogs.com/weiming4219/p/7833401.html
Copyright © 2011-2022 走看看