iOS-APNS(推送)

作者: 一个老实人 | 来源:发表于2018-04-23 20:08 被阅读1125次

    iOS-APNS(Apple Push Notification service)

    推送介绍: 在我们手机联网的时候,会自动与苹果服务器进行一个链接,这个链接叫长链接,所以我们才可以接受到推送通知,断网的情况下是不可能接受到推送通知的。

    (这里补充一个小知识:就是我们平时用的HTTP就是属于短链接,你请求一次,就给你反馈一次相应的数据或者状态信息)


    当我们的手机软件,已经退出了或者程序被杀死了,但是我们还是会受到推送消息。因为苹果为我们提供了一个服务器,这个服务器叫“APNS服务器”。这个服务器就是专门用来推送通知的。只要你的手机联网,你的手机就会与这个服务器进行一个长链接。

    举个例子:

    比如一个xx服务器想要单独给使用他们软件的其中一个用户推送一个消息,这个消息想想告诉用户一些信息如:版本更新消息或者购买某一个商品的状态信息等等。这个xx服务器就会把这条消息,和deviceToken信息发给苹果的APNS服务器,苹果APNS服务器就会根据这个deviceToken,找到对应的设备,然后推送给他。

    deviceToken:手机的UDID + APP的BundleID
    (每个手机的UDID都不一样,可以说是手机的生份证)
    屏幕快照 2018-04-23 下午7.40.45.png

    deviceToken的来源:(上图)

    deviceToken并不是在手机上生成的
    是当初手机安装这个软件的时候,它把手机的UDID和安装这个软件的BundleID发送给苹果的APNS服务器
    苹果的APNS服务器就会把接受的UDID和BundleID进行加密生成我们的deviceToken
    然后就会把这个deviceToken在返回给我们
    我们就可以拿到这个deviceToken传给xxx软件的服务器
    这个服务器就会把deviceToken存到数据库

    发送流程:

    服务器要发生一条通知消息,首先会去数据库找到,要推送用户的deviceToken
    找到了之后就会把推送的消息和deviceToken一起发给苹果的PANS服务器
    然后苹果的就会根据这个deviceToken,进行解析找到相应的设备,进行推送

    简单来说就是根据UDID找到你手机 在根据BundleID,找到手机上对应的BundleID

    一.获取deviceToken代码:

    iOS8以前
        /**
         *枚举类型
         UIRemoteNotificationTypeNone    = 0,   //不接收推送消息
         UIRemoteNotificationTypeBadge   = 1 << 0, 接收图标数字
         UIRemoteNotificationTypeSound   = 1 << 1, 接收时的音效
         UIRemoteNotificationTypeAlert   = 1 << 2, 接收消息文字弹窗
         UIRemoteNotificationTypeNewsstandContentAvailability = 1 << 3, 接收订阅消息
         */
        UIRemoteNotificationType  type = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert;
        /**
         当用户第一次启动程序的时候就获取deviceToken
         该方法在iOS8就过期le
         */
        //调用该方法,系统就会自动发送UDID和当前程序的BundleID到苹果的APNS服务器
        [application registerForRemoteNotificationTypes:type];
    
    
    iOS8~iOS10
    //ios8以后的
            /**
             UIUserNotificationTypeNone = 0,
             UIUserNotificationTypeBadge = 1 << 0,
             UIUserNotificationTypeSound = 1 << 1,
             UIUserNotificationTypeAlert = 1 << 2
             */
            UIUserNotificationType type = UIUserNotificationTypeBadge | UIUserNotificationTypeSound|UIUserNotificationTypeAlert;
            UIUserNotificationSettings *setting = [UIUserNotificationSettings settingsForTypes:type categories:nil];
            //注册通知类型
            [application registerUserNotificationSettings:setting];
            //申请使用通知
            [application registerForRemoteNotifications];
    
    iOS10.0后新的推送方式

    首先要添加头文件
    import <UserNotifications/UserNotifications.h>
    设置代理<UNUserNotificationCenterDelegate>

     UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
            center.delegate = self;
            [center requestAuthorizationWithOptions:(UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert) completionHandler:^(BOOL granted, NSError * _Nullable error) {
                
                if (!error) {
                    NSLog(@"succeeded!");
                }
            }];
    

    二.获取到deviceToken后会调

    /**
     获取到用户当前程序的deviceToken后会会调这个方法
     */
    -(void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken{
        
        NSLog(@"%@",deviceToken);
        //在这里我们就可以把deviceToken上传给我我们软件的服务器
        //deviceToken:就是我们需要的deviceToken;
    //    NSString *token=[NSString stringWithFormat:@"%@",deviceToken];
    //    token=[token stringByReplacingOccurrencesOfString:@"<" withString:@""];
    //    token=[token stringByReplacingOccurrencesOfString:@">" withString:@""];
    //    token=[token stringByReplacingOccurrencesOfString:@" " withString:@""];
    }
    

    三.获取推送的信息

    iOS7以前
    /*
     ios7以前苹果支持多任务, iOS7以前的多任务是假的多任务
     而iOS7开始苹果才真正的推出了多任务
     接收到远程服务器推送过来的内容就会调用
     注意: 只有应用程序是打开状态(前台/后台(程序没有杀死)), 才会调用该方法
     如果应用程序是关闭状态会调用didFinishLaunchingWithOptions
     */
    - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
    {
        /*
         如果应用程序在后台 , 只有用户点击了通知之后才会调用
         如果应用程序在前台, 会直接调用该方法
         即便应用程序关闭也可以接收到远程通知,但是改方法不会调用
         */
        NSLog(@"%@", userInfo);
        
    }
    
     如果应用程序是关闭状态会调用didFinishLaunchingWithOptions
    我们的推送消息就会放在launchOptions这里面
    
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
     // 1.取出数据
        NSDictionary *userInfo = launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey];
        
        if (userInfo) {
              NSLog(@"%@", userInfo);
         }
    
      return YES;
    }
    
    
    
    iOS7~iOS10.0
    //接收到远程服务器推送过来的内容就会调用
    // ios7以后用这个处理后台任务接收到得远程通知
    - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
    {
    
        NSLog(@"%@", userInfo);
        NSNumber *contentid =  userInfo[@"content-id"];
        if (contentid) {
            //注意: 在此方法中一定要调用这个调用block, 告诉系统是否处理成功.
            // 以便于系统在后台更新UI等操作
             /*
         UIBackgroundFetchResultNewData, 成功接收到数据
         UIBackgroundFetchResultNoData, 没有;接收到数据
         UIBackgroundFetchResultFailed 接收失败
         */completionHandler(UIBackgroundFetchResultNewData);
        }else
        {
            completionHandler(UIBackgroundFetchResultFailed);
        }
        
    }
    
    iOS10.0以后有2个方法
    /**
     *iOS10.0以后的方法
     */
    //App在后台运行及程序退出杀死 会调用的方法
    
    - (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(nonnull UNNotificationResponse *)response withCompletionHandler:(nonnull void (^)(void))completionHandler{
        
        
        NSDictionary *userInfo = response.notification.request.content.userInfo;
        NSLog(@"App在后台时候-%@", userInfo);
        
        completionHandler();
        
    }
    // App在前台时候回调:用户正在使用状态
    - (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
        
        NSDictionary *userInfo = notification.request.content.userInfo;
        NSLog(@"App在前台时候回调-%@", userInfo);
        
        //可以设置当收到通知后, 有哪些效果呈现(声音/提醒/数字角标)
        completionHandler(UNNotificationPresentationOptionBadge | UNNotificationPresentationOptionSound | UNNotificationPresentationOptionAlert);
        
    }
    

    在app进入后台的时候,app会进入休眠的状态,不会执行任何操作。如果我们想让app进入后台后,接受到了通知后,依然进行一些操作(更新界面)就要配置我的的工程

    1.开启多任务(后台运行模式)

    在iOS7以前虽然有了多任务,但是这个功能并不完善,到了iOS7以后,这个多任务才可以正常使用


    29DF90FF-3C22-45AB-8FD4-DB34815D6CEE.png
    2.通知的格式也要改一下

    后台推送
    支持系统:iOS7及以上
    推送格式:
    {"aps":{"content-available":1"},"content":"hhhh"}

    最后附上AppDelegate.m参考

    #import "AppDelegate.h"
    #import <UserNotifications/UserNotifications.h>
    
    @interface AppDelegate ()<UNUserNotificationCenterDelegate>
    
    @end
    
    @implementation AppDelegate
    
    
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        
        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以后的
            /**
             UIUserNotificationTypeNone = 0,
             UIUserNotificationTypeBadge = 1 << 0,
             UIUserNotificationTypeSound = 1 << 1,
             UIUserNotificationTypeAlert = 1 << 2
             */
            UIUserNotificationType type = UIUserNotificationTypeBadge | UIUserNotificationTypeSound|UIUserNotificationTypeAlert;
            UIUserNotificationSettings *setting = [UIUserNotificationSettings settingsForTypes:type categories:nil];
            //注册通知类型
            [application registerUserNotificationSettings:setting];
            //申请使用通知
            [application registerForRemoteNotifications];
            
        }else{
            /**
             *枚举类型
             UIRemoteNotificationTypeNone    = 0,   //不接收推送消息
             UIRemoteNotificationTypeBadge   = 1 << 0, 接收图标数字
             UIRemoteNotificationTypeSound   = 1 << 1, 接收时的音效
             UIRemoteNotificationTypeAlert   = 1 << 2, 接收消息文字弹窗
             UIRemoteNotificationTypeNewsstandContentAvailability = 1 << 3, 接收订阅消息
             */
            UIRemoteNotificationType  type = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert;
            /**
             当用户第一次启动程序的时候就获取deviceToken
             该方法在iOS8就过期le
             */
            //调用该方法,系统就会自动发送UDID和当前程序的BundleID到苹果的APNS服务器
            [application registerForRemoteNotificationTypes:type];
        }
        
        
        //取出推送通知:
        //当程序被杀死或者退出了,接受到的推送信息会保留在launchOptions中,当我们重新打开软件的时候再取出来
        //取出在程序退出的时候接受到的推送消息
        NSDictionary *userInfo = launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey];
        if (userInfo) {
            NSLog(@"%@", userInfo);
        }
        
        return YES;
    }
    
    
    /**
     获取到用户当前程序的deviceToken后会会调这个方法
     */
    -(void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken{
        
        NSLog(@"%@",deviceToken);
        
        //deviceToken:就是我们需要上传服务器的deviceToken;
    
    }
    
    /*
     *iOS7以前
     *ios7以前苹果支持多任务, iOS7以前的多任务是假的多任务
     *而iOS7开始苹果才真正的推出了多任务
     *接收到远程服务器推送过来的内容就会调用
     *注意: 只有应用程序是打开状态(前台/后台(程序没有杀死)), 才会调用该方法
     *如果应用程序是关闭状态会调用didFinishLaunchingWithOptions
     */
    - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
    {
        /*
         如果应用程序在后台 , 只有用户点击了通知之后才会调用
         如果应用程序在前台, 会直接调用该方法
         即便应用程序关闭也可以接收到远程通知,但是改方法不会调用
         */
        NSLog(@"%@", userInfo);
        
    }
    /**
     *ios7以后
     *ios7以后用这个处理后台任务接收到得远程通知
     *接收到远程服务器推送过来的内容就会调用
     */
    - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
    {
        
        NSLog(@"%@", userInfo);
        NSNumber *contentid =  userInfo[@"content-id"];
        if (contentid) {
            //注意: 在此方法中一定要调用这个调用block, 告诉系统是否处理成功.
            // 以便于系统在后台更新UI等操作
            /*
             UIBackgroundFetchResultNewData, 成功接收到数据
             UIBackgroundFetchResultNoData, 没有;接收到数据
             UIBackgroundFetchResultFailed 接收失败
             */
            completionHandler(UIBackgroundFetchResultNewData);
        }else
        {
            completionHandler(UIBackgroundFetchResultFailed);
        }
        
    }
    
    
    /**
     *iOS10.0以后的方法
     */
    //App在后台运行及程序退出杀死 会调用的方法
    
    - (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(nonnull UNNotificationResponse *)response withCompletionHandler:(nonnull void (^)(void))completionHandler{
        
        
        NSDictionary *userInfo = response.notification.request.content.userInfo;
        NSLog(@"App在后台时候-%@", userInfo);
        
        completionHandler();
        
    }
    // App在前台时候回调:用户正在使用状态
    - (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
        
        NSDictionary *userInfo = notification.request.content.userInfo;
        NSLog(@"App在前台时候回调-%@", userInfo);
        
        //可以设置当收到通知后, 有哪些效果呈现(声音/提醒/数字角标)
        completionHandler(UNNotificationPresentationOptionBadge | UNNotificationPresentationOptionSound | UNNotificationPresentationOptionAlert);
        
    }
    
    
    @end
    
    

    相关文章

      网友评论

        本文标题:iOS-APNS(推送)

        本文链接:https://www.haomeiwen.com/subject/gbillftx.html