码迷,mamicode.com
首页 > 移动开发 > 详细

iOS,推送通知

时间:2016-04-22 18:24:44      阅读:347      评论:0      收藏:0      [点我收藏+]

标签:

推送通知

推送通知跟NSNotification有所区别: 
1> NSNotification是抽象的,不可见的 
2> 推送通知是可见的(能用肉眼看到)

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

推送通知可以不让在前台运行的app,告知app内部发生了什么变化,比如:有新的内容,新消息等.

推送通知的使用: 
发出推送通知时,如果当前程序正运行在前台,那么推送通知就不会被呈现出来 
点击推送通知后,默认会自动打开发出推送通知的app 
不管app打开还是关闭,推送通知都能如期发出

推送通知有5种呈现效果: 
1. 在屏幕顶部显示一块横幅(显示具体内容) 
2. 在屏幕中间弹出一个UIAlertView(显示具体内容,使用较少) 
3. 在锁屏界面显示一块横幅(锁屏状态下,显示具体内容) 
4. 播放音效(提醒作用) 
5. 更新app图标的数字(说明新内容的数量)

推送通知分为本地推送通知和远程推送通知,下面一一介绍.

本地推送通知

本地推送通知不需要服务器的支持,不需要联网就可以发送通知.通常本地推送通知用于定时提醒用户,比如清理垃圾,淘宝购物,纪念日提醒等任务. 
在苹果官方给出了本地推送通知的一些属性,以及使用.

属性介绍:

  @property(nonatomic,copy) NSDate *fireDate; // 设置本地推送的时间
  @property(nonatomic,copy) NSTimeZone *timeZone; // 时区(一般设置为[NSTimeZone defaultTimeZone] ,跟随手机的时区)
  @property(nonatomic) NSCalendarUnit repeatInterval; // 没隔多久重复发出一次
  @property(nonatomic,copy) NSCalendar *repeatCalendar; // 设置日期
  @property(nonatomic,copy) CLRegion *region NS_AVAILABLE_IOS(8_0); // 比如某一个区域的时候发出通知
  @property(nonatomic,assign) BOOL regionTriggersOnce NS_AVAILABLE_IOS(8_0); // 进入区域是否重复
  @property(nonatomic,copy) NSDictionary *userInfo;  // 附加的额外信息
  @property(nonatomic,copy) NSString *alertBody; // 消息的内容
  @property(nonatomic) BOOL hasAction; // 是否显示alertAction的文字(默认是YES)
  @property(nonatomic,copy) NSString *alertAction;  // 设置锁屏状态下,显示的一个文字
  @property(nonatomic,copy) NSString *alertLaunchImage; // 启动图片
  @property(nonatomic,copy) NSString *soundName;   //  UILocalNotificationDefaultSoundName
  @property(nonatomic) NSInteger applicationIconBadgeNumber; // 应用图标右上角的提醒数字
  @property(nonatomic,copy) NSArray *scheduledLocalNotifications; // 获得被调度(定制)的所有本地推送通知(已经发出且过期的推送通知就算调度结束,会自动从这个数组中移除)

 

使用方法:

创建本地通知

UILocalNotification *localNoti = [[UILocalNotification alloc] init];

 

调度本地推送通知(调度完毕后,推送通知会在特地时间fireDate发出)

[[UIApplication sharedApplication] scheduleLocalNotification:localNoti];

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

 

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

 

注意: 
iOS8.0以后在本地推送通知上新加了一些新功能,为了用户体验,以及更加人性化,如果要使用本地通知,需要得到用户的许可. 
需要在AppDelegate中添加如下代码

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    /*
     UIUserNotificationTypeNone    = 0,      没有,没有本地通知
     UIUserNotificationTypeBadge   = 1 << 0, 接受图标右上角提醒数字
     UIUserNotificationTypeSound   = 1 << 1, 接受通知时候,可以发出音效
     UIUserNotificationTypeAlert   = 1 << 2, 接受提醒(横幅/弹窗)
     */
    // iOS8需要添加请求用户的授权
    if ([UIDevice currentDevice].systemVersion.floatValue >= 8.0) {
        UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge | UIUserNotificationTypeAlert | UIUserNotificationTypeSound categories:nil];
        [application registerUserNotificationSettings:settings];
    }
}

 

 

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

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

- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification;
  • 1
  • 1

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

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;

 

launchOptions参数通过UIApplicationLaunchOptionsLocalNotificationKey取出本地推送通知对象

若要实现界面的跳转,需要分清当前应用程序的所处状态,进行判断: 
1> 若是当前应用在后台运行,接收到通知时,要想进行界面的跳转,可以在didReceiveLocalNotification:方法中实现跳转界面的方法 
2> 若是当前的应用程序已经关闭,我们在前面说到,当应用关闭,推送通知也会如期发送.但此时,是不会走didReceiveLocalNotification:方法的,那我们只有didFinishLaunchingWithOptions:方法利用,launchOptions参数通过UIApplicationLaunchOptionsLocalNotificationKey取出本地推送通知对象,实现跳转的功能.

下面是演示代码:

#import "AppDelegate.h"

@interface AppDelegate ()

@end

@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    /*
     UIUserNotificationTypeNone    = 0,      没有,没有本地通知
     UIUserNotificationTypeBadge   = 1 << 0, 接受图标右上角提醒数字
     UIUserNotificationTypeSound   = 1 << 1, 接受通知时候,可以发出音效
     UIUserNotificationTypeAlert   = 1 << 2, 接受提醒(横幅/弹窗)
     */
    // iOS8需要添加请求用户的授权
    if ([UIDevice currentDevice].systemVersion.floatValue >= 8.0) {
        UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge | UIUserNotificationTypeAlert | UIUserNotificationTypeSound categories:nil];
        [application registerUserNotificationSettings:settings];
    }

    if (launchOptions[UIApplicationLaunchOptionsLocalNotificationKey]) {
        // 跳转界面

    }

    return YES;
}

/**
 *  如果应用在后台,通过点击通知的时候打开应用会来到该代理方法
 *  如果应用在前台,接受到本地通知就会调用该方法
 *
 *  @param notification 通过哪一个通知来这里
 */
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
    if (application.applicationState == UIApplicationStateActive) return;
    if (application.applicationState == UIApplicationStateInactive) {

        // 实现跳转
    }
}

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
    return YES;
}



#import "ViewController.h"

@interface ViewController ()

// 点击按钮之后添加通知
- (IBAction)addLocalNote;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    [[UIApplication sharedApplication] setApplicationIconBadgeNumber:0];
}

- (IBAction)addLocalNote {

    // 1.创建本地通知
    UILocalNotification *localNote = [[UILocalNotification alloc] init];

    // 设置什么时间弹出
    localNote.fireDate = [NSDate dateWithTimeIntervalSinceNow:5];

    // 设置弹出的内容
    localNote.alertBody = @"您有新消息";

    // 设置锁屏状态下,显示的一个文字
    localNote.alertAction = @"快点打开";


    // 是否显示alertAction的文字(默认是YES)
    localNote.hasAction = YES;

    // 设置音效
    localNote.soundName = UILocalNotificationDefaultSoundName;

    // 应用图标右上角的提醒数字
    localNote.applicationIconBadgeNumber = 1;

    // 设置UserInfo来传递信息
    localNote.userInfo = @{@"alertBody" : localNote.alertBody, @"applicationIconBadgeNumber" : @(localNote.applicationIconBadgeNumber)};

    // 2.调度通知
    [[UIApplication sharedApplication] scheduleLocalNotification:localNote];
}

 

远程推送通知

远程推送通知:就是通过网络从远程服务器推送给客户端的通知.

为什么需要远程推送通知? 
传统获取数据的局限性 
只要用户关闭了app,就无法跟app的服务器沟通,无法从服务器上获得最新的数据内容

远程推送通知可以解决以上问题 
不管用户打开还是关闭app,只要联网了,都能接收到服务器推送的远程通知

远程推送通知的使用 
所有的苹果设备,在联网状态下,都会与苹果的服务器建立长连接 
长连接: 只要联网了,就一直建立连接

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

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

远程推送功能机制

苹果给iOS和Mac添加了消息推送的功能,使得我们可以通过后台服务器给应用程序(APP)发送消息,不管APP是否正在使用,比如邮箱的来件提示功能。这项服务被称为Apple Push Notification service(APNs)。里面一共涉及到四个角色:APP、设备、APNs和应用后台服务器(Provider),其中APP、后台服务器和APNs之间使用deviceToken唯一的标识一个用户。 
技术分享

推送服务的工作流程:

APP向系统注册推送服务。
设备从APNs请求deviceToken。
通过代理方法将deviceToken返回给APP。
APP将deviceToken发送给应用后台服务器(Provider)。
应用后台服务器保存deviceToken,然后在需要推送通知的时候,给APNs发送信息,使用deviceToken标识所要送达的客户端。
APNs将后台服务器发过来的数据推送到设备。
设备将消息分发给应用程序。

在使用推送功能的时候,需要在开发者中心创建支持Push Notification的证书,并且将证书和私钥用于应用后台服务器与APNs之间通信。

我也写了一个比较易懂的远程推送流程图! http://blog.csdn.net/ismilesky/article/details/48324723

远程推送近年来,都是通过第三方进行实现,因为第三方推送的功能比较强大. 
推送平台: 百度推送 , 极光推送, 腾讯信鸽推送, 个推 
远程推送我们这里以极光推送(第三方)为例,进行测试.

极光远程推送的使用

如要使用极光第三方远程推送,我们需要集成iOS SDK,需要进行应用的配置,和环境配置.在开发者中心有 
developer.apple.com开发者账号 , iOS真机(iPhone、iPad、iPod)等。

远程推送应用配置过程:

  1. 创建支持远程推送功能的App ID
  2. 申请开发者证书,并选中刚刚创建的App ID
  3. 下载CER文件,并导入钥匙串管理
  4. 申请发布证书,并选中刚刚创建的App ID
  5. 下载CER文件,并导入钥匙串管理
  6. 检查App ID,确认证书已经指定

这些相关配置极光推送已经给了非常详细的文档资料, iOS SDK集成指南 :http://docs.jpush.io/guideline/ios_guide/ , iOS SDK调试指南 :http://docs.jpush.io/client/ios_tutorials/#ios-sdk, 只需要按照流程进行就可以.

实现代码:

#define kDeviceVersion  ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0)

#import "AppDelegate.h"
#import "APService.h"

@interface AppDelegate ()

@end

@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_7_1
    if (kDeviceVersion) {
        //可以添加自定义categories
        [APService registerForRemoteNotificationTypes:(UIUserNotificationTypeBadge | UIUserNotificationTypeSound |UIUserNotificationTypeAlert) categories:nil];
    } else {
        //categories 必须为nil
        [APService registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound |UIRemoteNotificationTypeAlert) categories:nil];
    }
#else
    //categories 必须为nil
    [APService registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound |UIRemoteNotificationTypeAlert) categories:nil];

#endif

    [APService setupWithOption:launchOptions];


    return YES;
}

#pragma mark - 获取device token (必须实现)
// 当得到苹果的APNs服务器返回的DeviceToken就会被调用
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
    NSLog(@"%@",deviceToken);
    // Required
    [APService registerDeviceToken:deviceToken];
}

#pragma mark - 获取device token失败
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
    NSLog(@"function == %s  line == %d  error == %@",__FUNCTION__,__LINE__,error);
}

// 接收到远程通知,触发方法和本地通知一致 (必须实现)
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
    // Required
    [APService handleRemoteNotification:userInfo];
}

#pragma mark - 使用后台的远程消息推送 (必须实现)
/**
 1> 在Capabilities中打开远程推送通知
 2> 实现该代理方法

远程消息数据格式:
 {"aps" : {"content-available" : 1},"content-id" : 42}

 执行completionHandler有两个目的
 1> 系统会估量App消耗的电量,并根据传递的UIBackgroundFetchResult 参数记录新数据是否可用
 2> 调用完成的处理代码时,应用的界面缩略图会自动更新

 注意:接收到远程通知到执行完网络请求之间的时间不能超过30秒

 if (userInfo) {
 int contentId = [userInfo[@"content-id"] intValue];

 ViewController *vc = (ViewController *)application.keyWindow.rootViewController;
 [vc loadDataWithContentID:contentId completion:^(NSArray *dataList) {
 vc.dataList = dataList;

 NSLog(@"刷新数据结束");

 completionHandler(UIBackgroundFetchResultNewData);
 }];
 } else {
 completionHandler(UIBackgroundFetchResultNoData);
 }

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

    // IOS 7 Support Required
    [APService handleRemoteNotification:userInfo];

    [[UIApplication sharedApplication]setApplicationIconBadgeNumber:0];

    // 判断应用程序在前台还是后台
    if (application.applicationState == UIApplicationStateActive) { // 活跃状态

       // 实现方法

    } else if (application.applicationState == UIApplicationStateInactive) {
        // 不活跃状态

        // 实现方法

    } else { // application.applicationState == UIApplicationStateBackground
        // 后台

        // 实现方法
    }
    /** 必须回调 */
    completionHandler(UIBackgroundFetchResultNewData);

}

测试时,运行完应用程序,要发送通知,进行推送的测试,真机收到通知才算成功. 

技术分享

iOS,推送通知

标签:

原文地址:http://www.cnblogs.com/W-Kr/p/5422290.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!