本地推送.极光推送.APNs推送

来源:互联网 发布:乐视手机网络不稳定 编辑:程序博客网 时间:2024/05/16 10:42

1.本地推送的简单应用
2.APNs介绍
3.使用极光推送向你的APP推送一条信息

一.本地推送

本地通知推送也叫闹钟通知, 这是通知中比较简单的一部分.
如果将app比喻成一个人, 某个controller比喻成身体的某一部分(手臂), 那么由手臂注册通知并且发送通知, 最后被大脑(AppDelegate)收到这个通知并作出处理.

file-list

下面我们模拟一个情景, 在ViewController中创建一个通知(闹钟)并且激活它, 然后在Appdelegate中收到这个通知, 并且弹窗AlertView显示.

ViewController.h

12
// 本地注册通知的方法+ (void)registerLocalNotification:(NSInteger)alertTime;

ViewController.m

1234567891011121314151617181920212223242526272829
+ (void)registerLocalNotification:(NSInteger)alertTime{    // 实例化一个本地通知对象.    UILocalNotification * notification = [[UILocalNotification alloc] init];        // 设置什么时间点(具体的时间)触发本地通知. 距离现在多少秒之后.    notification.fireDate = [NSDate dateWithTimeIntervalSinceNow:alertTime];        // 设置时区,default手机时区    notification.timeZone = [NSTimeZone defaultTimeZone];        // 设置重复间隔, 按秒计算.    notification.repeatInterval = kCFCalendarUnitSecond;        // 弹出的通知内容, 下拉菜单的通知.    notification.alertBody = @"快迟到了!";    // 气泡个数    notification.applicationIconBadgeNumber = 1;        // 通知被触发时播放声音吗?    notification.soundName = UILocalNotificationDefaultSoundName;        // 通知的参数    NSDictionary * userDict = [NSDictionary dictionaryWithObject:@"起床洗漱了" forKey:@"hurry"];    notification.userInfo = userDict;        // 最后一步, 将这个通知激活.    [[UIApplication sharedApplication] scheduleLocalNotification:notification];}

事实上, 这么写已经将闹钟激活了, 他确实会在alerttime秒之后向发送一个通知, 但是, 我们没有在Appdelegate中配置接受这个通知并作出响应. 那么这个通知实际上被我们丢弃了.

那么如何在Appdelegate中处理这个通知呢?, 有一个代理方法application:didReceiveLocalNotification是处理这个通知的.

AppDelegate.m

12345678910111213
#pragma mark本地通知代理// 做过iOS 开发的人对这个函数都会很熟悉,这是在程序结束启动,并即将运行时调用的,通常一些初始化的工作可以在这个函数中处理。- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification*)notification{    //在此时设置解析notification,并展示提示视图    NSString * message = [notification.userInfo valueForKey:@"hurry"];    UIAlertView * alert = [[UIAlertView alloc] initWithTitle:@"aaaa" message:message delegate:self cancelButtonTitle:@"取消" otherButtonTitles: nil];    [alert show];        // 既然已经查看了这个通知, 那么气泡就要减少一个    NSInteger badge = [[UIApplication  sharedApplication] applicationIconBadgeNumber];    badge --;    [UIApplication sharedApplication].applicationIconBadgeNumber = badge;}

以上代码并不完整.
我们并没有为app申请本体通知的权限:

AppDelegate.m的didFinishLaunchingWithOptions方法中

12345678910111213
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    // Override point for customization after application launch.        // ios8后,需要添加这个注册,才能得到授权    if ([[UIApplication sharedApplication] respondsToSelector:@selector(registerUserNotificationSettings:)]) {        UIUserNotificationType type =  UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound;        UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:type categories:nil];        [[UIApplication sharedApplication] registerUserNotificationSettings:settings];    }else{ // ios8之前的申请权限方法.        [application registerForRemoteNotificationTypes:UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound];    }    return YES;}

这样基本就完成了, 但是有一种情况, 比如闹钟响了, 我们点击了起床, 此时闹铃不应该再响了, 我们应该从本地通知中取消这个通知(根据key).

AppDelegate.m的application:didReceiveLocalNotification方法中, 我们在气泡减一操作之后, 调用这个页面的取消通知方法.

12
// 取消通知[ViewController cancelLocalNotificationWithKey:@"hurry"];

ViewController.h

12
// 根据传入的key, 移除本地通知+ (void)cancelLocalNotificationWithKey:(NSString *)key;

VidwController.m

1234567891011
+ (void)cancelLocalNotificationWithKey:(NSString *)key{    // 从当前的app中找出所有的本地通知.    NSArray * notificationArrray = [UIApplication sharedApplication].scheduledLocalNotifications;    // 如果按照key寻找userInfo, 不为空则说明找到了.    for (UILocalNotification * not in notificationArrray) {        if ([not.userInfo valueForKey:key]) {            [[UIApplication sharedApplication] cancelAllLocalNotifications];        }    }}

以上就是我们比较完整的需求.


二.苹果自家推送–APNs服务

下面来讲一下远程推送, 上面的推送不联网也能执行, 但是远程推送则不行.

等一下, 这个远程推送是什么意思? 为什么会有远程推送?

苹果的推送功能是ios3.0之后推出的, 也就是说, 一开始的苹果操作系统是没有这个功能. 那么为什么后来要加上这个推送呢? 没有推送行不行呢?

这个还真不行.

原因很简单, 苹果ios操作系统不支持真正意义上的多任务.
假设一种应用场景, 如果不支持多任务的话, 你正在聊qq, 忽然想去微信摇一摇, 切换到微信后, qq程序进入后台, 但是再也收不到消息了.

早期(2007年)的iphone就是这个样子. 除了几个系统工具, 如打电话, 发短信, 看地图, 发邮件外, 你不能保证用户自己的app同时运行. 等等, 说错了! 妈蛋那个时候iphone还没有app store呢, 你想装app都不行.

于是乎, 苹果推出了自己家的推送服务, 由苹果服务器手机推送一条通知, 手机根据推送过来的消息, 判断属于发给谁(发给哪个app), 然后向该app发送通知, 调用相应的代理方法, 最终的结果是, 你桌面上的app图标冒起了气泡, 桌面通知栏弹出一个条消息.

file-list

这就是远程推送, 看似不经意的一个动作, 包含了一整套的设计方案–APNs, 凝结了无数人的心血.

APNs(英文全称:Apple Push Notification Service),中文翻译为:苹果推送通知服务。顾名思义, 该服务由苹果提供并且维护.

在这里要特别的注意, 如果服务器使用推送的方式与APP发生交互, 那么你必须走APNs, 换而言之, 三方服务不能直接向你的手机推送消息, 必须通过APNs.

那么我们该如何理解APNs服务呢?

我们通过三张图来简单说明一下APNs的推送过程, 此图来自APNs百度百科.

  • 手机与服务器建立连接:
    file-list

    1.手机向APNs服务器发出初连接请求. 手机与服务器开始握手.
    2.服务器向设备返回服务器证书(Server Cerficate). 此证书的目的是为了表明服务器的身份.
    3.手机验证刚刚收到的证书合法性(Validate Server Cerficate), 如果验证成功, 则表明手机连接到了正确的服务器.(Validate: 证实,验证;确认;使生效, 它还有隐藏含义, 使证书生效).
    4.下面轮到手机向服务器发送证书(Device Cerficate), 此证书表明了手机的身份–有没有越狱? 是不是苹果机器?
    5.服务器验证手机是否合法.
    6.身份验证完毕.


  • 推送过程:

    1.你开发的APP, 从当前的手机系统iOS中读取手机的推送证书, 之后, iOS操作系统向APNs Server申请Device token.
    2.APNs Server返回Device token到你的手机, 再由iOS通知给你的APP.
    3.你的APP将获得的Device token, 发送到你的服务器, 可以是极光服务器, 可以是你们公司自己的服务器, 不管怎样, 你的服务器中要维护一张Device token的表. 这个表中, 记录了所有使用你APP的Device token.
    4.当你需要向某个用户发送推送时, 根据3维护的表, 找到该用户的Device token, 然后将Device token和需要推送的消息, 一起发送给 APNs Server
    5.最终, APNs将这条推送消息推送到用户APP中, 完成推送过程.

注意以上的两个过程建立连接推送过程, 建立连接是为了验证通信双方的身份, 我们关注的点应该在推送.


  • 你的服务器如何向用户群推送

    此过程是上图中的4,5步骤.不做赘述.

下面我们通过使用极光推送来具体的演示一下过程, 并且分析它.


三.极光推送

极光推送主要功能

  • 为 JPush Server 上报 Device Token,免除开发者管理 Device Token 的麻烦
  • 应用运行时,应用内 JPush 长连接可以持续地收到推送消息

极光推送的集成过程以及使用方法在官方文档中有着极为详细的说明, 这里引用一下, 不做赘述.

  • 极光推送SDK下载
  • 极光推送集成文档

下面讨论一些莫名其妙的东西.

* 一.didFinishLaunching

前面提到, 这个方法会在程序启动完成之后执行, 通常一些程序的初始化动作可以在这里执行.
所以, 推送的初始化也要在这里完成, 推送的注册(申请权限)根据iOS的版本不同略有不同, iOS8之前只需要一句话, 之后的版本则多几行.

123456789101112131415
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    // Required, 注册通知    if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) {        //可以添加自定义categories        [APService registerForRemoteNotificationTypes:( UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert) categories:nil];    } else {        //categories 必须为nil        [APService registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert) categories:nil];    }        // Required    [APService setupWithOption:launchOptions];        return YES;}

我们看最后一句:[APService setupWithOption:launchOptions];
launchOptions(下段文字来自百度知道:怎样判断app是通过推送消息启动的)
当应用程序启动时执行,应用程序启动入口。只在应用程序启动时执行一次。application参数用来获取应用程序的状态、变量. 字典参数:(NSDictionary *)launchOptions,该参数存储程序启动的原因。

  • 若用户直接启动,lauchOptions内无数据;
  • 若由其他应用程序通过openURL:启动,则UIApplicationLaunchOptionsURLKey对应的对象为启动URL(NSURL),UIApplicationLaunchOptionsSourceApplicationKey对应启动的源应用程序的bundle ID (NSString);
  • 若由本地通知启动,则UIApplicationLaunchOptionsLocalNotificationKey对应的是为启动应用程序的的本地通知对象(UILocalNotification);
  • 若由远程通知启动,则UIApplicationLaunchOptionsRemoteNotificationKey对应的是启动应用程序的的远程通知信息userInfo(NSDictionary);
  • 其他key还有UIApplicationLaunchOptionsAnnotationKey, UIApplicationLaunchOptionsLocationKey,
    UIApplicationLaunchOptionsNewsstandDownloadsKey.

如果要在启动时,做出一些区分,那就需要在下面的代码做处理。
所以, [APService setupWithOption:launchOptions];方法, 会根据启动类型, 对极光推送做一些配置.

* 二.获得token
123
- (void)application:(UIApplication *)applicationdidRegisterForRemoteNotificationsWithDeviceToken:(NSData *)pToken// &- (void)application:(UIApplication *)applicationdidFailToRegisterForRemoteNotificationsWithError:(NSError *)error

这两个方法是将设备的token传送到苹果的服务器的回调方法,在成功之后, 我们应该调用:[APService registerDeviceToken:deviceToken];方法, 将这个token发送到极光服务器(这里一定要注意, 我们选择由极光替我们维护这张token表, 如果你的公司有自己的推送服务器, 应该将此token发送到你公司的服务器, 自行维护这张表.)

* 三.接收处理方法.

如果程序在运行期间或者后台状态, 则如果推送消息会在下面的两个方法中执行, 注意, 两个方法作用一样, 你应该从中二选一, 苹果推荐你选择后者, 因为他提供了一个回调的句柄. 这个block的特别之处在于, 回调方法不是严格等待处理结束, 开始处理30s后, 此句柄会被调起.

123
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo// &-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler

userInfo结构

123456789
{    "aps" : {        "alert" : "You got your emails.",        "badge" : 9,        "sound" : "bingbong.aiff"    },    "acme1" : "bar",    "acme2" : 42}
0 0
原创粉丝点击