iOS-APNS(推送)

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
设置代理

 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 

@interface AppDelegate ()

@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(推送))