iOS-本地推送和远程推送,常用的三方推送和常用的测试方法,推送实现和原理详解
什么是消息推送
举一个常见的例子,我们的手机上经常会有弹出一些信息,例如QQ信息、微信信息等等,这就是常见的消息推送。
例如:
消息推送的类型:
- 在屏幕顶部显示一块横幅(显示具体内容)
- 在屏幕中间弹出一个UIAlertView(显示具体内容)
- 在锁屏界面显示一块横幅(锁屏状态下,显示具体内容)
- 更新app图标的数字(说明新内容的数量)
- 播放音效(提醒作用)
这是我们常见的推送消息的样式,我们可以在手机上自定义接收的消息如何展示。
在一些软件中,如果用户不小心关闭了我们的推送服务,我们也可以这样提示用户怎么打开允许接收推送服务(iOS8以后)。
注意:
-
发出推送通知时,如果当前程序正运行在前台,那么推送通知就不会被呈现出来
-
点击推送通知后,默认会自动打开发出推送通知的app
-
不管app打开还是关闭,推送通知都能如期发出
消息推送和平常的从服务器获取数据有什么不同?
- 当我们从服务器获取数据的时候,我们会
主动向服务器
发送消息,然后服务器才会给我们发送我们需要的信息;而消息推送是当我们不在聊天状态下,甚至是连QQ软件都没有打开的情况下,服务器主动向我们
发送消息,告诉我们一些信息。
当然了,消息推送和通知(NSNotification)可不一样,虽然它们的使用类名看起来有点相似。
- NSNotification是抽象的,不可见的
- 消息推送是可见(肉眼可见的)
本地推送
在iOS中,推送分为本地推送和远程推送,本地推送不需要网络(不需要服务器的支持),常见的应用场景例如:
-
事件提醒类的软件,到了我们自定义的时间,就会弹出一些信息告诉我们该干什么了。
-
记账类软件,会提醒我们的一些花销等等。
我们先来学习一下本地推送
相关使用的类(重要)
- 创建本地推送通知对象
UILocalNotification *ln = [[UILocalNotification alloc] init];
- 设置本地推送通知属性
//推送通知的触发时间(何时发出推送通知)
@property(nonatomic,copy) NSDate *fireDate;
//推送通知的具体内容
@property(nonatomic,copy) NSString *alertBody;
//在锁屏时显示的动作标题(完整标题:“滑动来” + alertAction)
@property(nonatomic,copy) NSString *alertAction;
//音效文件名
@property(nonatomic,copy) NSString *soundName;
//app图标数字
@property(nonatomic) NSInteger applicationIconBadgeNumber;
//每隔多久重复发一次推送通知
@property(nonatomic) NSCalendarUnit repeatInterval;
//点击推送通知打开app时显示的启动图片
@property(nonatomic,copy) NSString *alertLaunchImage;
//附加的额外信息
@property(nonatomic,copy) NSDictionary *userInfo;
//时区
@property(nonatomic,copy) NSTimeZone *timeZone;
(一般设置为[NSTimeZone defaultTimeZone] ,跟随手机的时区)
//调度本地推送通知(调度完毕后,推送通知会在特地时间fireDate发出)
[[UIApplication sharedApplication] scheduleLocalNotification:ln];
//获得被调度(定制)的所有本地推送通知
@property(nonatomic,copy) NSArray *scheduledLocalNotifications;
(已经发出且过期的推送通知就算调度结束,会自动从这个数组中移除)
//取消调度本地推送通知
- (void)cancelLocalNotification:(UILocalNotification *)notification;
- (void)cancelAllLocalNotifications;
//立即发出本地推送通知
- (void)presentLocalNotificationNow:(UILocalNotification *)notification;
- 用户点击推送消息进入app时的调用方法
//当用户点击本地推送通知,会自动打开app,这里有2种情况
//app并没有关闭,一直隐藏在后台
//让app进入前台,并会调用AppDelegate的下面方法(并非重新启动app)
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification;
//app已经被关闭(进程已死)
//启动app,启动完毕会调用AppDelegate的下面方法
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;
//launchOptions参数通过UIApplicationLaunchOptionsLocalNotificationKey取出本地推送通知对象
//当点击通知进入app时,launchOptions参数才会有值,当正常启动app时,launchOptions为null
注意:
在iOS 8.0中,如果要使用本地通知,需要得到用户的许可
在didFinishLaunchingWithOptions方法中添加如下代码:
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert categories:nil];
[application registerUserNotificationSettings:settings];
实例:
//在需要的地方注册本地消息推送
// 1.创建本地通知
UILocalNotification *localNote = [[UILocalNotification alloc] init];
// 2.设置本地通知的信息
// 2.1.设置提示信息
localNote.alertBody = @"吃饭了吗?";
// 2.2.设置通知弹出的时间
localNote.fireDate = [NSDate dateWithTimeIntervalSinceNow:5.0];
// 2.3.设置滑块显示的文字
localNote.alertAction = @"快点";
// 2.4.是否让上面的文字生效
localNote.hasAction = NO;
// 2.5.设置通知中心的标题
localNote.alertTitle = @"你大哥";
// 2.6.设置通知的声音
localNote.soundName = @"buyao.wav";
// 2.7.设置应用程序图标右上角的数字
localNote.applicationIconBadgeNumber = 10;
// 3.调度通知
//调度前要先把原来的通知取消
UIApplication *app = [UIApplication sharedApplication];
[app cancelAllLocalNotifications];
[app scheduleLocalNotification:localNote];
在appdelegate类中实现相应的跳转方法
#import "AppDelegate.h"
#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];
}
return YES;
}
//程序没有关闭时,点击通知进入app才会调用,如果将程序完全退出,点击通知进入app时只会调用上面的方法,不会调用这个方法
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
// 在这里写跳转代码
// 如果是应用程序在前台,依然会收到通知,但是收到通知之后不应该跳转
if (application.applicationState == UIApplicationStateActive) return;
if (application.applicationState == UIApplicationStateInactive) {
// 当应用在后台收到本地通知时执行的跳转代码
[self jumpToSession];
}
}
- (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];
}
@end
远程推送
先介绍一下iOS中远程推送的原理:
我们先要明确一点,所有的iOS设备收到的远程推送消息都是通过苹果的服务器发出来的。我们自己公司的服务器或者第三方的推送服务器都是将要发送给我们的推送消息先推给苹果的服务器,然后再由苹果的服务器发送给我们。
如下图:
所以,我们的苹果设备在联网的情况下,都会默认和苹果的服务器保持一个长连接(这里不解释长连接的概念,你可以理解成是有一条线一直在两者之间联系着,为了保持服务器不断开和我们设备的联系,我们的设备默认每隔一段时间会向服务器发送心跳包(一个很小的文件),来告诉苹果服务器不要和我们的设备断开连接)。
原理图讲解
下面详细解释一下iOS中的远程推送原理
上图中1-8的步骤就可以很好的解释远程推送的过程了,而客户端需要做的只有几个步骤:
-
1:发送设备的UDID和
应用的Bundle Identifier
给APNs服务器 -
2:经苹果加密生成一个
deviceToken -
3:发送当前用户的deviceToken
和用户的标志(比如id或者qq)到自己公司的服务器或者第三方推送服务器 -
4:监听通知的点击事件
其余的步骤由服务器端实现:
-
4:自己的服务器或者第三方推送服务器将客户端发送过来的用户信息保存在自己的服务器中
-
5:有人发送消息的时候,从服务器中(根据deviceToken)查询要发给谁
-
6:查询到要发送给某人以后,将信息发送给苹果服务器
-
7:苹果服务器根据得到的deviceToken和信息,查到要接受信息的设备和app,将信息发送给用户。
调试iOS的远程推送功能, 必备条件:
1.真机
2.调试推送需要的证书文件
1> aps_development.cer : 某台电脑就能调试某个app的推送服务
2> iphone5_qq.mobileprovision : 某台电脑就能利用某台设备调试某个程序
三.发布具有推送服务的app,需要的证书文件
1> aps_production.cer : 如果发布的程序中包含了推送服务,就必须安装这个证书
2> qq.mobileprovision : 某台电脑就能发布某个程序
实际操作
下面就开始真正的使用一下远程推送功能吧。
证书配置01 – 创建App ID
配置明确的App ID
大概步骤如下:
先选择明确的App ID
配置远程推送的调试证书
配置远程推送的发布证书(使用第二种方法配置)
新建项目,将Bundle ID改成和上面配置的成相同名字。
如果还是不行,检查这里
将配置好的证书下载后安装。
接下来就可以开始处理远程推送的消息了:
- 1、向苹果注册我们的设备,并获取到deviceToken
注意:
在iOS7和iOS8中的注册方法不一样
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// 请求获取DeviceToken
if ([[UIDevice currentDevice].systemVersion doubleValue] >= 8.0) {
// 1.获取发送通知的权限
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:nil];
[application registerUserNotificationSettings:settings];
// 2.注册远程通知
[application registerForRemoteNotifications];
} else {
[application registerForRemoteNotificationTypes:UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound];
}
return YES;
}
//获取到deviceToken
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
NSLog(@"%@", deviceToken);
}
- 2、处理远程通知的消息
这里有两个方法,注意两者的区别,更具需要调用
//这个方法可以处理当用户点击消息进入前台做一些操作
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
NSLog(@"%@", userInfo);
}
//这个方法可以实现在用户手机收到消息就可以在后台进行一些操作,例如更新UI
//不过,这个方法要先设置后台模式,方法如下:
/*
1.开启后台模式
2.调用completionHandler,告诉系统你现在是否有新的数据更新
3.userInfo添加一个字段:"content-available" : "1" : 只要添加了该字段,接受到通知都会在后台运行
*/
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
UIView *redView = [[UIView alloc] init];
redView.frame = CGRectMake(100, 100, 100, 100);
redView.backgroundColor = [UIColor redColor];
[self.window.rootViewController.view addSubview:redView];
completionHandler(UIBackgroundFetchResultFailed);
}
添加后台模式方法:
测试工具介绍
下面介绍一种测试远程通知的工具PushMeBaby
- PushMeBaby是一款用来测试ANPs的开源Mac项目
- 它充当了服务器的作用,用法非常简单
- 它负责将内容提交给苹果的APNs服务器,苹果的APNs服务器再将内容推送给用户的设备
- PushMeBaby的主页
https://github.com/stefanhafeneger/PushMeBaby
使用步骤:
- 注释掉不要的错误
-
填写必要信息
-
deviceToken:用于找到设备的令牌
-
payload:推送的内容
-
- 将推送的调试证书改为名apns.cer,添加到PushMeBaby项目中
- command + R启动程序,然后点击Push
接下来就可以在设备上接收到远程推送通知
常用的第三方推送(极光推送)
什么是JPush
一套远程推送解决方案,支持android和iOS两个平台
它能够快捷地为iOS App增加推送功能,减少集成APNs需要的工作量、开发复杂度
更多的信息,可以参考JPush官方网站:https://www.jpush.cn
集成iOS SDK的步骤可以参考
http://docs.jpush.cn/pages/viewpage.action?pageId=2621727