IOS 推送通知 本地推送和远程推送

什么是推送通知?

首先明确:**此处的推送通知跟我们的”NSNotification”没有半毛钱关系
可以理解为: 向用户推送一条信息来通知用户某件事情
作用: 可以在APP退到后台,或者关闭时;继续推送一条消息告诉用户某件事情

推送通知的应用场景?

  • (1) 一些任务管理APP,会在任务时间即将到达时,通知你做该任务;
    (2) 健身App定时提醒你应该健身了;
    (3) 买过电影票后,提前半小时告诉你,电影即将开场;
    (4) 当你QQ或者微信收到消息时,即使退到后台,或者关闭APP,也可以收到信息通知告诉我们;
    (5) 电商APP,推送一条消息通知我们有新品上架等等

推送通知的分类

  • 本地推送通知

    “本地”可以理解为”不联网”;即使没有网络情况下,也可以推送通知消息
    应用场景: 确定知道未来某个时间点应该提醒用户什么
    通知发送方:开发人员负责在app内部发送

  • 远程推送通知

    与“本地”相对,表示,必须在联网情况下才会向用户推送通知消息
    远程推送服务,又称为APNs(Apple Push Notification Services)

    应用场景:

    1. 不确定未来某个时间点应该提醒用户什么,临时性的
    2. 当APP彻底退出时也想继续让用户获取一些最新消息
  • 使用原则: 谁能确定通知时间和内容, 谁就可以发送(开发人员在APP内部通过代码发送=本地通知; 服务器可以确定通知时间和内容=远程通知)*

远程推送的呈现效果

image.png

本地推送通知

在iOS8.0之后 使用本地通知需要得到用户的许可 在didFinishLaunchingWithOptions里面添加请求

if(系统版本 >= 8.0)
{
    // 注册接收通知的类型
    UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:nil];
    [application registerUserNotificationSettings:settings];

    // 注册允许接收远程推送通知
    [application registerForRemoteNotifications];
}
else
{
    // 如果是iOS7.0,使用以下方法注册
    [application registerForRemoteNotificationTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound];
}

//swfit:

 if #available(iOS 8.0, *)
        {
            // 注册接收通知的类型
            let type = UIUserNotificationType.alert.rawValue | UIUserNotificationType.badge.rawValue | UIUserNotificationType.sound.rawValue
            let settings = UIUserNotificationSettings(types: UIUserNotificationType(rawValue: type), categories: nil)
            
            UIApplication.shared.registerUserNotificationSettings(settings)
            // 注册允许接收远程推送通知
            UIApplication.shared.registerForRemoteNotifications()
        }
          

发送一个本地通知

@IBAction func puchNotionfication(_ sender: Any)
    {
    // 如果是ios8.0以前, 以下代码, 可以直接发送一个本地通知,
    // 但是, 如果是ios8.0以后, 你需要主动的请求授权, 才可以
    // 通知显示的条件
    // 必须不能再前台
        
        //1.创建一个t本地通知
        let localNoti = UILocalNotification()
        //2. 设置通知内容
        localNoti.alertBody = "这是一个好日字"
        //3. 设置发送通知的时间触发时间
        localNoti.fireDate = Date(timeIntervalSinceNow: 4) 
    
        //重复周期
        // localNoti.repeatInterval = .weekday
        //设置滑动文字
        localNoti.hasAction = true
        localNoti.alertAction = "回复"
        // 启动图片(当用户点击了本地通知, 启动我们APP 的时候, 带的启动图片)
               // 如果是在ios9.0以前, 当锁屏界面, 出现一个通知, 用户点击了通知, 启动APP 的时候, 会自动将我们设置的图片, 当做启动图像 来显示
               // ios9.0, 这个属性, 不太灵
               // 如果这个图片,找不到, 会使用系统默认的启动图片
        localNoti.alertLaunchImage = "2"
        
        
               // 设置通知弹框的标题
               // 标题, 这对于, 通知中心的通知有效
        if #available(iOS 8.2, *)
        {
            localNoti.alertTitle = "斗地主"
        }

        // 设置图标右上角的数字(0 代表不显示)
        localNoti.applicationIconBadgeNumber = 3
         // userInfo 额外信息
        localNoti.userInfo = ["name":"哥哥", "sex":"女"]
        

    
        //应用程序级别的操作 ,调度本地通知,完成之后,会在特定的fireDate发出通知

        UIApplication.shared.scheduleLocalNotification(localNoti)
        
    }

其他的属性和方法

调度本地推送通知(调度完毕后,推送通知会在特地时间fireDate发出)
[[UIApplication sharedApplication] scheduleLocalNotification:ln];

获得被调度(定制)的所有本地推送通知
@property(nonatomic,copy) NSArray *scheduledLocalNotifications;
(已经发出且过期的推送通知就算调度结束,会自动从这个数组中移除)

取消调度本地推送通知
- (void)cancelLocalNotification:(UILocalNotification *)notification;
- (void)cancelAllLocalNotifications;

立即发出本地推送通知
- (void)presentLocalNotificationNow:(UILocalNotification *)notification;


每隔多久重复发一次推送通知
@property(nonatomic) NSCalendarUnit repeatInterval;

点击推送通知打开app时显示的启动图片
@property(nonatomic,copy) NSString *alertLaunchImage;

附加的额外信息
@property(nonatomic,copy) NSDictionary *userInfo;

时区
@property(nonatomic,copy) NSTimeZone *timeZone;
(一般设置为[NSTimeZone defaultTimeZone] ,跟随手机的时区)

点击本地通知

当用户点击本地推送通知,会自动打开app,这里有2种情况

  1. app并没有关闭,一直隐藏在后台
    让app进入前台,并会调用AppDelegate的下面方法(并非重新启动app)
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification;
  1. app已经被关闭(进程已死)
    启动app,启动完毕会调用AppDelegate的下面方法
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;
launchOptions参数通过UIApplicationLaunchOptionsLocalNotificationKey取出本地推送通知对象

添加一些额外的操作

IMG_0497.PNG
func registerAuthor()
    {
        // Override point for customization after application launch.
           if #available(iOS 8.0, *)
           {
               // 注册接收通知的类型
               let type = UIUserNotificationType.alert.rawValue | UIUserNotificationType.badge.rawValue | UIUserNotificationType.sound.rawValue
            
               
            
            
            //1.创建z一组操作行为
            let category = UIMutableUserNotificationCategory()
            //1.1设置组标识
            category.identifier = "select"
            //1.2设置组里面的行为
            let action1 = UIMutableUserNotificationAction()
            action1.identifier = "queding"
            action1.title = "确定"
            // behavior todo
                       
            // 代表, 用户如果点击了这个动作, 拉到底, 是在前台运行这个动作, 还是在后台
            action1.activationMode = .foreground
             // 必须要解锁之后, 行为才会执行(如果activationMode, 是前台状态, 那这个属性, 就会被忽略)
            action1.isAuthenticationRequired = true
            // 是否是破坏性行为(会使用一个红色的标识, 来标识这个按钮)
            action1.isDestructive = false
            
            //1.1设置组标识
            category.identifier = "select"
            
            //1.2设置组里面的行为
            let action2 = UIMutableUserNotificationAction()
            action2.identifier = "huifu"
            action2.title = "回复"
            
            // behavior todo
            if #available(iOS 9.0, *)
            {
                action2.behavior = .textInput
                action2.parameters = [UIUserNotificationTextInputActionButtonTitleKey: "确定"]
                    
            }
                                      
            // 代表, 用户如果点击了这个动作, 拉到底, 是在前台运行这个动作, 还是在后台
            action2.activationMode = .background
            // 必须要解锁之后, 行为才会执行(如果activationMode, 是前台状态, 那这个属性, 就会被忽略)
            action2.isAuthenticationRequired = false
            // 是否是破坏性行为(会使用一个红色的标识, 来标识这个按钮)
            action2.isDestructive = false
            
            
            let actions = [action1, action2]
            
            // 如果针对于弹框样式的通知
            // default 代表, 最多可以显示4个按钮
            // minimal, 代表,最多可以显示2个按钮
            category.setActions(actions, for: .default)
            
            //附加操作行为组
            let categorys : Set = [category]
            
               let settings = UIUserNotificationSettings(types: UIUserNotificationType(rawValue: type), categories: categorys)
                UIApplication.shared.registerUserNotificationSettings(settings)
            
               // 注册允许接收远程推送通知
               UIApplication.shared.registerForRemoteNotifications()
           }
               
        
    }
     // completionHandler, 系统提供的回调代码块, 执行这个代码块, 到时候, 系统会采集一些信息
    func application(_ application: UIApplication, handleActionWithIdentifier identifier: String?, for notification: UILocalNotification, completionHandler: @escaping () -> Void)
    {
        print(identifier,notification)
        print("old")
        completionHandler()
    }
    // 9.0
    // 如果实现了这个方法, 那么上面一个方法, 就不再执行
    func application(_ application: UIApplication, handleActionWithIdentifier identifier: String?, for notification: UILocalNotification, withResponseInfo responseInfo: [AnyHashable : Any], completionHandler: @escaping () -> Void) {
        print("new")
        print(identifier,responseInfo)
        completionHandler()
    }

远程推送

什么是远程推送通知

  • 顾名思义,就是从远程服务器推送给客户端的通知(需要联网)
  • 远程推送服务,又称为APNs(Apple Push Notification Services

为什么需要远程推送通知?

传统获取数据的局限性
只要用户关闭了app,就无法跟app的服务器沟通,无法从服务器上获得最新的数据内容
不管用户打开还是关闭app,只要联网了,都能接收到服务器推送的远程通知

所有的苹果设备,在联网状态下,都会与苹果的服务器建立长连接

  • 什么是长连接
    只要联网了,就一直建立连接

  • 长连接的作用
    时间校准
    系统升级
    查找我的iPhone
    .. ...

  • 长连接的好处
    数据传输速度快
    数据保持最新状态

获取deviceToken

苹果需要用户的UDID和bundleID


获取过程

qq案例分析

  1. app 发送设备的UDID和
    应用的Bundle Identifier
    给APNs服务器

  2. 经苹果加密生成一个
    deviceToken 返还给当前app

  3. app发送当前用户的deviceToken
    和用户的标志(比如id或者qq) 给qq服务器

  4. qq服务器将用户的deviceToken存进数据库

  5. 当有人发送消息 李四的手机(昵称:李四 QQ:56789)
    发给张三(QQ12345):吃饭没?

  6. 消息先到qq服务器,然后去数据库查询张三的deviceToken

  7. qq服务器通知苹果服务器
    deviceTokoen:888
    body:李四:吃饭没?

  8. 苹果服务器通过deviceToken找到张三现在的设备

一.开发iOS程序的推送功能, iOS端需要做的事

1.请求苹果获得deviceToken
2.得到苹果返回的deviceToken,发送deviceToken给公司的服务器

  1. 监听用户对通知的点击

二.调试iOS的远程推送功能, 必备条件:

1.真机

2.调试推送需要的证书文件
1> aps_development.cer : 某台电脑就能调试某个app的推送服务
2> iphone5_qq.mobileprovision : 某台电脑就能利用某台设备调试某个程序

三.发布具有推送服务的app

1> aps_production.cer : 如果发布的程序中包含了推送服务,就必须安装这个证书
2> qq.mobileprovision : 某台电脑就能发布某个程序

制作证书

截屏2020-05-27下午4.42.59.png
截屏2020-05-27下午4.43.18.png
截屏2020-05-27下午4.43.09.png
截屏2020-05-27下午4.43.25.png

截屏2020-05-27下午4.43.35.png
截屏2020-05-27下午4.43.44.png

注册远程推送通知

客户端如果想接收APNs的远程推送通知,必须先注册(得到用户的授权)
一般在App启动完毕后就马上注册

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // 注册远程通知
       UIRemoteNotificationType type = UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound;
    [application registerForRemoteNotificationTypes:type];
    return YES;
}
  • 注册成功后会调用AppDelegate的下面方法,得到设备的deviceToken
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
    NSLog(@"%@", deviceToken);
}

点击远程推送通知

当用户点击远程推送通知,会自动打开app,这里有2种情况
app并没有关闭,一直隐藏在后台
让app进入前台,并会调用AppDelegate的下面方法(并非重新启动app)

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo;

app已经被关闭(进程已死)
启动app,启动完毕会调用AppDelegate的下面方法

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;
launchOptions参数通过UIApplicationLaunchOptionsRemoteNotificationKey取出服务器返回的字典内容

你可能感兴趣的:(IOS 推送通知 本地推送和远程推送)