iOS消息推送机制

作者: Little_Dragon | 来源:发表于2015-10-05 22:33 被阅读19618次

    推送通知跟NSNotification不同
    1.NSNotification是抽象的,不可见的
    2.推送通知是可见的

    iOS中提供了2中推送通知
    1.本地推送通知(Local Notification)
    2.远程推送通知(Remote Notification)

    推送的作用:可以让不在前台运行的app,告知客户app内部发生的事情.(QQ消息推送,微信消息推送等等)

    推送通知的呈现效果:
    1.在屏幕顶部显示的一条横幅
    2.在屏幕中间弹出一个UIAlertView
    3.在锁屏界面显示一块横幅
    4.跟新app图标的数字
    5.播放音效

    本地通知

    1.不需要服务器支持(无需联网)就能发出的推送通知
    2.使用场景: 定时类任务(闹钟,简单的游戏等等)

    本地通知推送的实现很简单:
    1.创建本地推送通知对象
    [[UILocalNotification alloc] init]创建一个本地通知
    2.设置本地通知的相关属性
    必须设置的属性
    2.1.推送通知的触发时间(何时发出推送通知)
    @property(nonatomic,copy) NSDate *fireDate
    2.2.推送通知的具体内容
    @property(nonatomic,copy) NSString *alertBody
    2.3.在锁屏时显示的动作标题(完整测标题:"滑动来" + alertAction)
    @property(nonatomic,copy) NSString *alertAction
    2.4.设置锁屏界面alertAction是否有效
    localNote.hasAction = YES;
    2.5.app图标数字
    @property(nonatomic,assign) NSInteger applicationIconBadgeNumber
    2.6.调度本地推送通知(调度完毕后,推动通知会在特定时间fireDate发出)
    [[UIApplication shareApplication] scheduleLocalNotification:ln]
    可以进行设置的设置
    2.7.设置通知中心通知的标题
    localNote.alertTitle = @"222222222222";
    2.8.设置音效(如果不设置就是系统默认的音效, 设置的话会在mainBundle中查找)
    localNote.soundName = @"buyao.wav";
    2.9.每隔多久重复发一次推送通知
    @property(nonatomic) NSCalendarUnit repeatInterval
    2.10.点击推送通知打开app时显示的启动图片(mainBundle 中提取图片)
    @property(nonatomic,copy) NSSring *alertLaunchImage
    2.11.附加的额外信息
    @property(nonatomic,copy) NSDictionary *userInfo
    2.12.时区
    @property(nonatomic,copy) NSTimeZone *timeZone
    (一般设置为[NSTimeZone defaultTimeZone],跟随手机的时区)

    --代码实现过程:


    本地通知.gif
    /*
     @property(nonatomic,copy) NSDate *fireDate;
     @property(nonatomic,copy) NSTimeZone *timeZone; 时区
     
     @property(nonatomic) NSCalendarUnit repeatInterval; 重复间隔(枚举)
     @property(nonatomic,copy) NSCalendar *repeatCalendar; 重复日期(NSCalendar)
     
     @property(nonatomic,copy) CLRegion *region 设置区域(设置当进入某一个区域时,发出一个通知)
     
     @property(nonatomic,assign) BOOL regionTriggersOnce YES,只会在第一次进入某一个区域时发出通知.NO,每次进入该区域都会发通知
     
     @property(nonatomic,copy) NSString *alertBody;      
     
     @property(nonatomic) BOOL hasAction;                是否隐藏锁屏界面设置的alertAction
     @property(nonatomic,copy) NSString *alertAction;    设置锁屏界面一个文字
     
     @property(nonatomic,copy) NSString *alertLaunchImage;   启动图片
     @property(nonatomic,copy) NSString *alertTitle
     
     @property(nonatomic,copy) NSString *soundName;
     
     @property(nonatomic) NSInteger applicationIconBadgeNumber;
     
     @property(nonatomic,copy) NSDictionary *userInfo; // 设置通知的额外的数据
     */
    
    - (IBAction)addLocalNote:(id)sender {
        // 1.创建一个本地通知
        UILocalNotification *localNote = [[UILocalNotification alloc] init];
        
        // 2.设置本地通知的一些属性(通知发出的时间/通知的内容)
        // 2.1.设置通知发出的时间
        localNote.fireDate = [NSDate dateWithTimeIntervalSinceNow:5.0];
        // 2.2.设置通知的内容
        localNote.alertBody = @"吃饭了吗?";
        // 2.3.设置锁屏界面的文字
        localNote.alertAction = @"查看具体的消息";
        // 2.4.设置锁屏界面alertAction是否有效
        localNote.hasAction = YES;
        // 2.5.设置通过点击通知打开APP的时候的启动图片(无论字符串设置成什么内容,都是显示应用程序的启动图片)
        localNote.alertLaunchImage = @"111";
        // 2.6.设置通知中心通知的标题
        localNote.alertTitle = @"222222222222";
        // 2.7.设置音效
        localNote.soundName = @"buyao.wav";
        // 2.8.设置应用程序图标右上角的数字
        localNote.applicationIconBadgeNumber = 1;
        // 2.9.设置通知之后的属性
        localNote.userInfo = @{@"name" : @"张三", @"toName" : @"李四"};
        
        // 3.调度通知
        [[UIApplication sharedApplication] scheduleLocalNotification:localNote];
    }
    

    当消息被推送过来时,我们需要点击推送消息,来完成一些特定的任务.不如更新界面什么的(监听本地推送通知的点击)

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

    1.app没有关闭,只是一直隐藏在后台
    让app进入前台,并会调用AppDelegate的下面的方法(并非重新启动app)

    点击本地通知.gif
    - (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
    ----代码实现
    - (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
    {
        // 在这里写跳转代码
        // 如果是应用程序在前台,依然会收到通知,但是收到通知之后不应该跳转
        if (application.applicationState == UIApplicationStateActive) return;
        
        if (application.applicationState == UIApplicationStateInactive) {
            // 当应用在后台收到本地通知时执行的跳转代码
            [self jumpToSession];
        }
        
        NSLog(@"%@", notification);
    }
    
    - (void)jumpToSession
    {
        UILabel *redView = [[UILabel alloc] init];
        redView.backgroundColor = [UIColor redColor];
        redView.frame = CGRectMake(0, 100, 300, 400);
        redView.numberOfLines = 0;
        // redView.text = [NSString stringWithFormat:@"%@", launchOptions];
        [self.window.rootViewController.view addSubview:redView];
    }
    

    2.app已经被关闭(进程被杀死)

    点击本地通知.gif
    启动app,启动完毕会调用AppDelegate的下面的方法
    - (BOOL)application:(UIApplication *)application didFinishLaunchWithOptions:(NSDictionary *)launchOptions;
    launchOptions参数通过UIApplicationLaunchOptionsLocalNotificationKey取出本地推送通知对象
    需要特别注意的是:在iOS8.0以后本地通知有了一些变化,如果要使用本地通知,需要得到用户的许可.
    didFinishLaunchWithOptions方法中添加如下代码:
    
    #define IS_iOS8 ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0)
    
     if (IS_iOS8) {
            UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge | UIUserNotificationTypeAlert | UIUserNotificationTypeSound categories:nil];
            [application registerUserNotificationSettings:settings];
        }
    

    -----代码实现相关操作

    #define IS_iOS8 ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0)
    
    @interface AppDelegate ()
    
    @end
    
    @implementation AppDelegate
    
    
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        
        /*
         UIUserNotificationTypeNone    = 0,      不发出通知
         UIUserNotificationTypeBadge   = 1 << 0, 改变应用程序图标右上角的数字
         UIUserNotificationTypeSound   = 1 << 1, 播放音效
         UIUserNotificationTypeAlert   = 1 << 2, 是否运行显示横幅
         */
        
        [application setApplicationIconBadgeNumber:0];
        
        if (IS_iOS8) {
            UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge | UIUserNotificationTypeAlert | UIUserNotificationTypeSound categories:nil];
            [application registerUserNotificationSettings:settings];
        }
        
        // 如果是正常启动应用程序,那么launchOptions参数是null
        // 如果是通过其它方式启动应用程序,那么launchOptions就值
        if (launchOptions[UIApplicationLaunchOptionsLocalNotificationKey]) {
            // 当被杀死状态收到本地通知时执行的跳转代码
            // [self jumpToSession];
            UILabel *redView = [[UILabel alloc] init];
            redView.backgroundColor = [UIColor redColor];
            redView.frame = CGRectMake(0, 100, 300, 400);
            redView.numberOfLines = 0;
            redView.text = [NSString stringWithFormat:@"%@", launchOptions];
            [self.window.rootViewController.view addSubview:redView];
        }
        
        return YES;
    }
    
    远程推送(Remote Notification)

    1.从远程服务器推送给客户端的通知(需要联网)
    2.远程推送服务, 苹果起名为:APNS (Apple Push Notification Services)
    解决问题:只要联网了, 就能够接收到服务器推送的远程通知
    使用须知:
    所有的苹果设备,在联网状态下,都会与苹果服务器建立长连接.
    1.长连接:一直连接,客户端与服务器
    2.长连接作用:
    1>事件校准
    2>系统升级
    3>查找我的iPhone等....
    3.长连接的好处
    1>数据传输速度快
    2>数据保持最新状态

    官方结实长连接的使用

    1.获得deviceToken的过程

    Snip20151005_1.png Snip20151005_2.png

    1>客户端向苹果服务APNS,发送设备的UDID和英语的Bundle Identifier.
    2>经苹果服务器加密生成一个deviceToken
    3>将当前用户的deviceToken(用户标识),发送给自己应用的服务器
    4>自己的服务器,将得到的deviceToken,进行保存

    2.利用deviceToken进行数据传输,推送通知

    Snip20151005_3.png

    5>需要推送的时候,将消息和deviceToken一起发送给APNS,苹果服务器,再通过deviceToken找到用户,并将消息发给用户

    这里不再演示关于证书的配置, 简单的只进行说明步骤:
    1> 创建明确的AppID,只有明确的AppID才能进行一些特殊的操作
    2>真机调试的APNS SSL证书
    3>发布程序的APNS SSL证书
    4>生成描述文件
    [依次安装证书, 再装描述]

    注册远程推送通知:

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

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        
        if ([[UIDevice currentDevice].systemVersion doubleValue] >= 8.0) {
            // 1.注册UserNotification,以获取推送通知的权限
            UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge categories:nil];
            [application registerUserNotificationSettings:settings];
            
            // 2.注册远程推送
            [application registerForRemoteNotifications];
        } else {
            [application registerForRemoteNotificationTypes:UIRemoteNotificationTypeNewsstandContentAvailability | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound];
        }
        
        return YES;
    }
    

    2.注册成功后, 调用AppDelegate的方法,获取到用户的deviceToken

    - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
    {
        // <32e7cf5f 8af9a8d4 2a3aaa76 7f3e9f8e 1f7ea8ff 39f50a2a e383528d 7ee9a4ea>
        // <32e7cf5f 8af9a8d4 2a3aaa76 7f3e9f8e 1f7ea8ff 39f50a2a e383528d 7ee9a4ea>
        NSLog(@"%@", deviceToken.description);
    }
    

    3.点击推送通知,和本地一样有两种状况.
    1> app没有关闭,只是一直隐藏在后台
    让app进入前台, 并调用下面的方法(app没有重新启动)
    过期的方法:

    // 当接受到远程退职时会执行该方法(当进入前台或者应用程序在前台)
    - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
    {
        NSLog(@"%@", userInfo);
        
        UIView *redView = [[UIView alloc] init];
        redView.backgroundColor = [UIColor redColor];
        redView.frame = CGRectMake(100, 100, 100, 100);
        [self.window.rootViewController.view addSubview:redView];
    }
    

    苹果系统建议使用下面的方法:

    /*
     1.开启后台模式
     2.调用completionHandler,告诉系统你现在是否有新的数据更新
     3.userInfo添加一个字段:"content-available" : "1" : 只要添加了该字段,接受到通知都会在后台运行
     */
    - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
    {
        NSLog(@"%@", userInfo);
        UIView *redView = [[UIView alloc] init];
        redView.backgroundColor = [UIColor redColor];
        redView.frame = CGRectMake(100, 100, 100, 100);
        [self.window.rootViewController.view addSubview:redView];
        
        completionHandler(UIBackgroundFetchResultNewData);
    }
    

    2>app已经关闭,需要重新开启,---基本实现方法和本地通知yi'zhi

    相关文章

      网友评论

      • 西门欥雪:简明易懂。:+1:
      • IT小斯:你好 我是java开发的需要app ios版的消息推送 ios代码看不懂你有现成的资源吗 项目组只写了Android的 现在我需要实现ios这个
      • aa2e0aba1c58:主要原理蛮清晰透彻;不过我倒有一个疑问,集成友盟 1.4.0版本 ,角标会有变化吗?!
      • 蜿蜒花骨朵:很厉害,也很详细,👍
      • myk:很详细,谢谢
      • 橙夭夭_Zz:楼主能问下,目前正研究消息推送这块的内容,作为产品狗,在产品设计与逻辑上如何进行设计,还是统统交给程序猿了?
        Little_Dragon:@橙夭夭_Zz 也要进行说明
        橙夭夭_Zz:@Little_Dragon 那推送时机 和推送内容呢?
        Little_Dragon:@橙夭夭_Zz 推送声音,震动。 提醒数字, 内部响应。 都是需要产品去进行说明的
      • ca04a13f364c:很赞 谢谢 :smiley:
      • 大哉沧海:很给力,轻松了解ios推送基本逻辑。
      • 叁號選手:你好根据你的做法 目前没法收到本地推送!请问是什么问题吗?
      • 聂飞缘:想问一个问题,推送证书被同事删除了会影响现在的app的推送功能
        Little_Dragon:@聂飞缘 主要是看, 自己设定的 appID下 有没有push , 没有的话,就按最开始创建的那样一步步创建, 然后把所有 绑定你以前push文件的地方, 都改成现在的push文件
        聂飞缘:@Little_Dragon 重新创建之后还要生成描述文件吗
        Little_Dragon:@聂飞缘 应用是否已经上线, 若已经上线就没事. 若没有上线, 则查看下 苹果账号, 点开你的 appIDs->找到对应的appID , 点开->edit-> 查看对应的push上的证书是否已被revoke掉了. 没有revoke 就没事, 已经revoke 就重新创建吧
      • 广锅锅:写得很清楚,谢谢你解决了我的问题。
        Little_Dragon:@广锅锅 不客气,.
      • 爬树的蚂蚁:写的真好,一看就明白
        Little_Dragon:@爬树的蚂蚁 谢谢
      • 819e6e93a666:你好,我想问一下,APP退到后台,然后收到本地推送,但是我不点击通知栏进入,而是点击icon进入,这样怎么获取到通知的内容?
        Little_Dragon: @我是毒毒毒毒毒药 在后台的程序是可以监听到消息的传递的,通过回调函数拿到传递值info,做事情。但一般不这么做,苹果认为如果来通知你不进行点击,就认为你对通知的事情不关心,所以不必给你跳转想要的结果。
      • toplee:写的挺好的,想问一下,qq消息的区分,qq在前台,后台,被杀死,的情况下,我们收到消息是远程推送,本地推送,还是长链接啊??
        toplee:@風無 可以加你qq吗?请教一下,
        Little_Dragon: @toplee 被杀死也是远程推送。他应该借用了苹果的apns服务器
        Little_Dragon: @toplee 前台的话,手机当前程序,是socket长链接。后台是远程推送。有些公司会把特定节日作为本地推送搞。但是一半很少。本地推送适合于闹钟以及单机游戏等
      • lizhi_boy:总结得很好!!!
        Little_Dragon: @荔枝_boy 谢谢
      • 3939f4121f25:很喜欢加油
        Little_Dragon:@3939f4121f25 谢谢支持
      • Theyouth:好东西
        Little_Dragon:@Theyouth 谢谢

      本文标题:iOS消息推送机制

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