003-消息推送
一、前言
推送分为远程推送和本地推送。
二、远程推送
1.概念
1)所谓远程推送指的是从服务器推送到客户端的通知(需要联网),远程推送又称为APNs
2)远程推送的好处:传统的获取数据方法有局限性(用户只能在App打开时发送数据请求来获取服务器的数据)
3)使用须知:所有的苹果设备,在联网状态下,都会与苹果的服务器保持建立长连接(长连接:数据传输速度快、数据保持最新)
2.推送原理
1)用户在联网状态与苹果的APNS服务器保持着长连接
2)用户在App完成完成后,会向苹果的APNS服务器发送自己的设备ID和App的BoundleID
3)苹果将用户设备ID和用户所安装App的BoundleID加密形成一个deviceToken,并通过AppDelegate方法返回给用户
4)用户安装完App,当第一次打开应用,就会向App服务器发送自已的设备ID和deviceToken
5)App服务器拿到用户ID和deviceToken后,就会将它们存放在App服务器的数据库中
6)当需要发送推送消息时,App服务器就会从数据库中查找对应用户ID,从而找到相应的deviceToken,并且将推送消息与deviceToken一并发送给苹果的APNS服务器
7)苹果APNS服务器通过deviceToken找到相应的用户设备中安装的相应App,将消息发送过去
3.使用远程推送(不使用任何第三方)
1)首先我们必须去Apple Developer开发者中心制作推送证书和推送证书配置文件
2)代码
1 // AppDelegate.m文件 2 #import "AppDelegate.h" 3 4 @interface AppDelegate () 5 6 @end 7 8 @implementation AppDelegate 9 10 11 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 12 13 // 当用户第一次启动程序时就会获取deviceToken 14 // 只要调用该方法,系统就会自动发送UUID和App的BunleID到苹果的APNs服务器 15 if ([UIDevice currentDevice].systemVersion.doubleValue <= 8.0) { 16 UIRemoteNotificationType type = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert; 17 [application registerForRemoteNotificationTypes:type]; 18 } else { 19 UIUserNotificationType type = UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert; 20 UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:type categories:nil]; 21 [application registerUserNotificationSettings:settings]; 22 // 申请使用通知 23 [application registerForRemoteNotifications]; 24 } 25 26 // 取出推送数据 27 NSDictionary *userInfo = launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]; 28 // 判断是否有远程消息推送 29 if (userInfo) { 30 // 如果有需要在这里处理... 31 // 这里专门用来处理程序处于关闭状态时接收到的远程消息 32 // .... 33 } 34 35 return YES; 36 } 37 38 #pragma mark - 获取用户对应当前应用程序的deviceToken时就会调用 39 - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(nonnull NSData *)deviceToken 40 { 41 // d4cf32c1 eceea0a9 ceace1da f1f24833 b2d81673 9d935d11 03553527 908dac12 42 NSLog(@"deviceToken = %@", deviceToken); 43 } 44 45 #pragma mark - iOS7以前,接收到服务器推送过来的消息就会调用 46 // 如果应用程序在后台,只有用户点击了推送消息,才会调用(但是iOS8以后苹果有了多任务,我们可以打开多任务开关) 47 // 如果应用程序在前台,会直接调用 48 // 注意:只有应用程序是打开状态(前台/后台),才会调用该方法 49 // 注意:如果应用程序是关闭状态(死亡),会调用didFinishLaunchingWithOptions,那么这个方法中,推送信息会放在launchOptions参数之中 50 - (void)application:(UIApplication *)application didReceiveRemoteNotification:(nonnull NSDictionary *)userInfo 51 { 52 NSLog(@"userInfo = %@", userInfo); 53 // 这个方法与下面的这个方法是一样的,只不过一个是用于iOS8之前,一个是用于配合iOS8之后的多任务 54 #if 0 55 // 创建UILabel 56 static int count = 0; 57 count++; 58 UILabel *label = [[UILabel alloc] init]; 59 label.frame = CGRectMake(0, 250, 200, 200); 60 label.numberOfLines = 0; 61 label.textColor = [UIColor whiteColor]; 62 label.backgroundColor = [UIColor redColor]; 63 label.text = [NSString stringWithFormat:@"%@\n %d", userInfo, count]; 64 [self.window.rootViewController.view addSubview:label]; 65 #endif 66 } 67 68 #pragma mark - iOS7以后,接收到服务器推送过来的消息就会调用 69 // iOS8以后用这个方法处理后台任务接收到远程通知,可以配合iOS8以后推出的多任务 70 // iOS7以后都会调用 71 - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler 72 { 73 // UIBackgroundFetchResultNewData // 成功接收到数据 74 // UIBackgroundFetchResultNoData // 没有接收到数据 75 // UIBackgroundFetchResultFailed // 接收失败 76 77 // 取出推送数据 78 NSNumber *contentId = userInfo[@"content-id"]; 79 if (contentId) { 80 // 创建UILabel 81 UILabel *label = [[UILabel alloc] init]; 82 label.frame = CGRectMake(0, 250, 200, 200); 83 label.numberOfLines = 0; 84 label.textColor = [UIColor whiteColor]; 85 label.backgroundColor = [UIColor redColor]; 86 label.text = [NSString stringWithFormat:@"\n %@", contentId]; 87 [self.window.rootViewController.view addSubview:label]; 88 89 // 注意:在此方法中一定要调用这个block,告诉系统是否处理成功,以便于系统在后台中去更新UI等操作 90 completionHandler(UIBackgroundFetchResultNewData); 91 92 } else { 93 // 注意:在此方法中一定要调用这个block,告诉系统是否处理成功,以便于系统在后台中去更新UI等操作 94 completionHandler(UIBackgroundFetchResultFailed); 95 } 96 } 97 98 @end
4.JPush(极光推送)
1)登录注册极光推送的官方网站
2)按照JPush推送的iOS教程一步步来
这里只是提供制作证书的步骤:






















3)代码集成
1 // AppDelegate.m文件 2 #import "AppDelegate.h" 3 #import "JPUSHService.h" 4 5 @interface AppDelegate () 6 7 @end 8 9 @implementation AppDelegate 10 11 12 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 13 { 14 15 if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) { 16 // 可以添加自定义categories 17 [JPUSHService registerForRemoteNotificationTypes:(UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert) categories:nil]; 18 19 } else { 20 // categories 必须为nil 21 [JPUSHService registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert) categories:nil]; 22 } 23 24 // 启动极光推送的SDK 25 // 参数1:launchingOption 启动参数 26 // 参数2:appKey 应用必须的唯一标识(参考JPush相关文档获取) 27 // 参数3:channel 发布渠道(可选) 28 // 参数4:isProduction 是否生产环境(开发状态:NO 生产状态:YES) 29 // 参数5:advertisingIdentifier 广告标识符IDFA(如不需要使用IDFA,传nil) 30 // 如需继续使用pushConfig.plist文件声明appKey等配置内容,请依旧使用[JPUSHService setupWithOption:launchOptions]方式初始化 31 [JPUSHService setupWithOption:launchOptions appKey:@"7ec12ec1b6f2ccde18fa39bf" channel:@"Publish channel" apsForProduction:NO advertisingIdentifier:nil]; 32 33 return YES; 34 } 35 36 #pragma mark - 获取用户对应当前应用程序的deviceToken时就会调用 37 - (void)application:(UIApplication *)application 38 didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken 39 { 40 // 获取deviceToken后,将deviceToken发送给JPush管理 41 [JPUSHService registerDeviceToken:deviceToken]; 42 } 43 44 #pragma mark - iOS7以前,接收到服务器推送过来的消息就会调用 45 // 如果应用程序在后台,只有用户点击了推送消息,才会调用(但是iOS8以后苹果有了多任务,我们可以打开多任务开关) 46 // 如果应用程序在前台,会直接调用 47 // 注意:只有应用程序是打开状态(前台/后台),才会调用该方法 48 // 注意:如果应用程序是关闭状态(死亡),会调用didFinishLaunchingWithOptions,那么这个方法中,推送信息会放在launchOptions参数之中 49 - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo 50 { 51 [JPUSHService handleRemoteNotification:userInfo]; 52 } 53 54 #pragma mark - iOS7以后,接收到服务器推送过来的消息就会调用 55 // iOS8以后用这个方法处理后台任务接收到远程通知 56 // 这个可以配合iOS8之后苹果推出的多任务 57 - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler 58 { 59 NSLog(@"userInfo = %@", userInfo); 60 #if 0 61 userInfo = { 62 "_j_msgid" = 3648087063; 63 aps = { 64 alert = "\U4f60\U6709\U65b0\U7684\U7248\U672c\U9700\U8981\U66f4\U65b0"; 65 badge = 1; 66 "content-available" = 1; 67 sound = default; 68 }; 69 } 70 #endif 71 72 // 设置角标(清空角标) 73 // 程序在后台或者在前台,直接不用设置角标 74 // 程序在关闭状态,才有角标更新,然后点击进入前台,角标清0 75 [application setApplicationIconBadgeNumber:0]; 76 77 // UIBackgroundFetchResultNewData // 成功接收到数据 78 // UIBackgroundFetchResultNoData // 没有接收到数据 79 // UIBackgroundFetchResultFailed // 接收失败 80 [JPUSHService handleRemoteNotification:userInfo]; 81 // 注意:在此方法中一定要调用这个block,告诉系统是否处理成功,以便于系统在后台中去更新UI等操作 82 completionHandler(UIBackgroundFetchResultNewData); 83 } 84 85 #pragma mark - 注册JPush通知失败 86 - (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error 87 { 88 NSLog(@"Error: %@", error); 89 } 90 91 @end
三、本地推送
1.概念
顾名思义,本地通知就是不需要联网就能够发出来的推送通知(不需要服务器的支持)
2.使用场景
常用来提醒用户完成一些任务;比如:清理垃圾、记账的App等等;一些不需要再联网使用的App,往往需要使用本地通知
3.代码实例
1 // ViewController.m文件 2 #import "ViewController.h" 3 4 @interface ViewController () 5 6 @end 7 8 @implementation ViewController 9 10 - (void)viewDidLoad 11 { 12 [super viewDidLoad]; 13 14 [self initUI]; // 界面 15 } 16 17 #pragma mark - 界面 18 - (void)initUI 19 { 20 // addNoteBtn 21 CGFloat addNoteBtnX = 20; 22 CGFloat addNoteBtnY = 100; 23 CGFloat addNoteBtnW = (self.view.bounds.size.width - addNoteBtnX * 2) / 2.0 - 10; 24 CGFloat addNoteBtnH = 35; 25 UIButton *addNoteBtn = [UIButton buttonWithType:UIButtonTypeSystem]; 26 addNoteBtn.frame = CGRectMake(addNoteBtnX, addNoteBtnY, addNoteBtnW, addNoteBtnH); 27 [addNoteBtn setTitle:@"注册本地通知" forState:UIControlStateNormal]; 28 addNoteBtn.titleLabel.font = [UIFont boldSystemFontOfSize:17]; 29 addNoteBtn.tintColor = [UIColor whiteColor]; 30 addNoteBtn.backgroundColor = [UIColor blackColor]; 31 [addNoteBtn addTarget:self action:@selector(addNoteBtnClick:) forControlEvents:UIControlEventTouchUpInside]; 32 [self.view addSubview:addNoteBtn]; 33 34 // removeNoteBtn 35 CGFloat removeNoteBtnX = CGRectGetMaxX(addNoteBtn.frame) + 10; 36 CGFloat removeNoteBtnY = addNoteBtn.frame.origin.y; 37 CGFloat removeNoteBtnW = addNoteBtn.bounds.size.width; 38 CGFloat removeNoteBtnH = addNoteBtn.bounds.size.height; 39 UIButton *removeNoteBtn = [UIButton buttonWithType:UIButtonTypeSystem]; 40 removeNoteBtn.frame = CGRectMake(removeNoteBtnX, removeNoteBtnY, removeNoteBtnW, removeNoteBtnH); 41 [removeNoteBtn setTitle:@"移除本地通知" forState:UIControlStateNormal]; 42 removeNoteBtn.titleLabel.font = [UIFont boldSystemFontOfSize:17]; 43 removeNoteBtn.tintColor = [UIColor whiteColor]; 44 removeNoteBtn.backgroundColor = [UIColor blackColor]; 45 [removeNoteBtn addTarget:self action:@selector(removeNoteBtnClick:) forControlEvents:UIControlEventTouchUpInside]; 46 [self.view addSubview:removeNoteBtn]; 47 } 48 49 #pragma mark - 点击事件 50 // 1.注册本地通知 51 - (void)addNoteBtnClick:(UIButton *)sender 52 { 53 // 1.创建本地通知对象 54 UILocalNotification *localNote = [[UILocalNotification alloc] init]; 55 56 // 2.参数设置 57 // 指定通知发送时间(指定5秒后发送通知) 58 localNote.fireDate = [NSDate dateWithTimeIntervalSinceNow:5]; 59 // 注意:在真实开发中一般情况下还是需要指定时区(让通知的时间跟随当前时区) 60 localNote.timeZone = [NSTimeZone defaultTimeZone]; 61 // 指定通知内容 62 localNote.alertBody = @"这是通知的内容"; 63 // 指定锁屏界面的信息 64 localNote.alertAction = @"这是锁屏界面的信息"; 65 // 注册通知时可以指定将来点击通知之后需要传递的数据 66 localNote.userInfo = @{@"name" : @"Frank", @"age" : @"26", @"phone" : @"12345678912"}; 67 // 设置应用程序的提醒图标 68 localNote.applicationIconBadgeNumber = 998; 69 // 设置通知重复的周期 70 localNote.repeatInterval = NSCalendarUnitSecond; 71 // 设置点击通知进入程序时候的启动图片 72 localNote.alertLaunchImage = @"Default"; 73 // 收到通知播放的音乐 74 localNote.soundName = @"buyao.wav"; 75 76 // 3.注册通知 77 UIApplication *application = [UIApplication sharedApplication]; 78 [application scheduleLocalNotification:localNote]; 79 } 80 // 2.移除本地通知 81 - (void)removeNoteBtnClick:(UIButton *)sender 82 { 83 UIApplication *application = [UIApplication sharedApplication]; 84 // 清空所有本地通知 85 [application cancelAllLocalNotifications]; 86 // 清空指定本地通知 87 // [application cancelLocalNotification:nil]; 88 } 89 90 #pragma mark - 本地通知(UILocalNotification)知识点 91 // 1.指定通知发送的时间 92 // @property(nullable, nonatomic,copy) NSDate *fireDate; 93 94 // 2.指定通知发送的时区 95 // @property(nullable, nonatomic,copy) NSTimeZone *timeZone; 96 97 // 3.重复的周期(接收的是枚举值) 98 // @property(nonatomic) NSCalendarUnit repeatInterval; 99 100 // 4.重复周期(接收的是日历对象) 101 // @property(nullable, nonatomic,copy) NSCalendar *repeatCalendar; 102 103 // 5.通知的内容 104 // @property(nullable, nonatomic,copy) NSString *alertBody; 105 106 // 6.是否需要滑动事件(默认为YES) 107 // @property(nonatomic) BOOL hasAction; 108 109 // 7.锁屏状态的标题 110 // @property(nullable, nonatomic,copy) NSString *alertAction; 111 112 // 8.点击通知后的启动图片名 113 // @property(nullable, nonatomic,copy) NSString *alertLaunchImage; 114 115 // 9.收到通知播放的音乐 116 // @property(nullable, nonatomic,copy) NSString *soundName; 117 118 // 10.图标提醒数字 119 // @property(nonatomic) NSInteger applicationIconBadgeNumber; 120 121 // 11.额外的信息 122 // @property(nullable, nonatomic,copy) NSDictionary *userInfo; 123 124 @end

浙公网安备 33010602011771号