什么是推送通知?
首先明确:**此处的推送通知跟我们的”NSNotification”没有半毛钱关系
可以理解为: 向用户推送一条信息来通知用户某件事情
作用: 可以在APP退到后台,或者关闭时;继续推送一条消息告诉用户某件事情
推送通知的应用场景?
- (1) 一些任务管理APP,会在任务时间即将到达时,通知你做该任务;
(2) 健身App定时提醒你应该健身了;
(3) 买过电影票后,提前半小时告诉你,电影即将开场;
(4) 当你QQ或者微信收到消息时,即使退到后台,或者关闭APP,也可以收到信息通知告诉我们;
(5) 电商APP,推送一条消息通知我们有新品上架等等
推送通知的分类
-
本地推送通知
“本地”可以理解为”不联网”;即使没有网络情况下,也可以推送通知消息
应用场景: 确定知道未来某个时间点应该提醒用户什么
通知发送方:开发人员负责在app内部发送 -
远程推送通知
与“本地”相对,表示,必须在联网情况下才会向用户推送通知消息
远程推送服务,又称为APNs(Apple Push Notification Services)应用场景:
- 不确定未来某个时间点应该提醒用户什么,临时性的
- 当APP彻底退出时也想继续让用户获取一些最新消息
使用原则: 谁能确定通知时间和内容, 谁就可以发送(开发人员在APP内部通过代码发送=本地通知; 服务器可以确定通知时间和内容=远程通知)*
远程推送的呈现效果
本地推送通知
在iOS8.0之后 使用本地通知需要得到用户的许可 在didFinishLaunchingWithOptions里面添加请求
if(系统版本 >= 8.0)
{
// 注册接收通知的类型
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:nil];
[application registerUserNotificationSettings:settings];
// 注册允许接收远程推送通知
[application registerForRemoteNotifications];
}
else
{
// 如果是iOS7.0,使用以下方法注册
[application registerForRemoteNotificationTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound];
}
//swfit:
if #available(iOS 8.0, *)
{
// 注册接收通知的类型
let type = UIUserNotificationType.alert.rawValue | UIUserNotificationType.badge.rawValue | UIUserNotificationType.sound.rawValue
let settings = UIUserNotificationSettings(types: UIUserNotificationType(rawValue: type), categories: nil)
UIApplication.shared.registerUserNotificationSettings(settings)
// 注册允许接收远程推送通知
UIApplication.shared.registerForRemoteNotifications()
}
发送一个本地通知
@IBAction func puchNotionfication(_ sender: Any)
{
// 如果是ios8.0以前, 以下代码, 可以直接发送一个本地通知,
// 但是, 如果是ios8.0以后, 你需要主动的请求授权, 才可以
// 通知显示的条件
// 必须不能再前台
//1.创建一个t本地通知
let localNoti = UILocalNotification()
//2. 设置通知内容
localNoti.alertBody = "这是一个好日字"
//3. 设置发送通知的时间触发时间
localNoti.fireDate = Date(timeIntervalSinceNow: 4)
//重复周期
// localNoti.repeatInterval = .weekday
//设置滑动文字
localNoti.hasAction = true
localNoti.alertAction = "回复"
// 启动图片(当用户点击了本地通知, 启动我们APP 的时候, 带的启动图片)
// 如果是在ios9.0以前, 当锁屏界面, 出现一个通知, 用户点击了通知, 启动APP 的时候, 会自动将我们设置的图片, 当做启动图像 来显示
// ios9.0, 这个属性, 不太灵
// 如果这个图片,找不到, 会使用系统默认的启动图片
localNoti.alertLaunchImage = "2"
// 设置通知弹框的标题
// 标题, 这对于, 通知中心的通知有效
if #available(iOS 8.2, *)
{
localNoti.alertTitle = "斗地主"
}
// 设置图标右上角的数字(0 代表不显示)
localNoti.applicationIconBadgeNumber = 3
// userInfo 额外信息
localNoti.userInfo = ["name":"哥哥", "sex":"女"]
//应用程序级别的操作 ,调度本地通知,完成之后,会在特定的fireDate发出通知
UIApplication.shared.scheduleLocalNotification(localNoti)
}
其他的属性和方法
调度本地推送通知(调度完毕后,推送通知会在特地时间fireDate发出)
[[UIApplication sharedApplication] scheduleLocalNotification:ln];
获得被调度(定制)的所有本地推送通知
@property(nonatomic,copy) NSArray *scheduledLocalNotifications;
(已经发出且过期的推送通知就算调度结束,会自动从这个数组中移除)
取消调度本地推送通知
- (void)cancelLocalNotification:(UILocalNotification *)notification;
- (void)cancelAllLocalNotifications;
立即发出本地推送通知
- (void)presentLocalNotificationNow:(UILocalNotification *)notification;
每隔多久重复发一次推送通知
@property(nonatomic) NSCalendarUnit repeatInterval;
点击推送通知打开app时显示的启动图片
@property(nonatomic,copy) NSString *alertLaunchImage;
附加的额外信息
@property(nonatomic,copy) NSDictionary *userInfo;
时区
@property(nonatomic,copy) NSTimeZone *timeZone;
(一般设置为[NSTimeZone defaultTimeZone] ,跟随手机的时区)
点击本地通知
当用户点击本地推送通知,会自动打开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取出本地推送通知对象
添加一些额外的操作
func registerAuthor()
{
// Override point for customization after application launch.
if #available(iOS 8.0, *)
{
// 注册接收通知的类型
let type = UIUserNotificationType.alert.rawValue | UIUserNotificationType.badge.rawValue | UIUserNotificationType.sound.rawValue
//1.创建z一组操作行为
let category = UIMutableUserNotificationCategory()
//1.1设置组标识
category.identifier = "select"
//1.2设置组里面的行为
let action1 = UIMutableUserNotificationAction()
action1.identifier = "queding"
action1.title = "确定"
// behavior todo
// 代表, 用户如果点击了这个动作, 拉到底, 是在前台运行这个动作, 还是在后台
action1.activationMode = .foreground
// 必须要解锁之后, 行为才会执行(如果activationMode, 是前台状态, 那这个属性, 就会被忽略)
action1.isAuthenticationRequired = true
// 是否是破坏性行为(会使用一个红色的标识, 来标识这个按钮)
action1.isDestructive = false
//1.1设置组标识
category.identifier = "select"
//1.2设置组里面的行为
let action2 = UIMutableUserNotificationAction()
action2.identifier = "huifu"
action2.title = "回复"
// behavior todo
if #available(iOS 9.0, *)
{
action2.behavior = .textInput
action2.parameters = [UIUserNotificationTextInputActionButtonTitleKey: "确定"]
}
// 代表, 用户如果点击了这个动作, 拉到底, 是在前台运行这个动作, 还是在后台
action2.activationMode = .background
// 必须要解锁之后, 行为才会执行(如果activationMode, 是前台状态, 那这个属性, 就会被忽略)
action2.isAuthenticationRequired = false
// 是否是破坏性行为(会使用一个红色的标识, 来标识这个按钮)
action2.isDestructive = false
let actions = [action1, action2]
// 如果针对于弹框样式的通知
// default 代表, 最多可以显示4个按钮
// minimal, 代表,最多可以显示2个按钮
category.setActions(actions, for: .default)
//附加操作行为组
let categorys : Set<UIUserNotificationCategory> = [category]
let settings = UIUserNotificationSettings(types: UIUserNotificationType(rawValue: type), categories: categorys)
UIApplication.shared.registerUserNotificationSettings(settings)
// 注册允许接收远程推送通知
UIApplication.shared.registerForRemoteNotifications()
}
}
// completionHandler, 系统提供的回调代码块, 执行这个代码块, 到时候, 系统会采集一些信息
func application(_ application: UIApplication, handleActionWithIdentifier identifier: String?, for notification: UILocalNotification, completionHandler: @escaping () -> Void)
{
print(identifier,notification)
print("old")
completionHandler()
}
// 9.0
// 如果实现了这个方法, 那么上面一个方法, 就不再执行
func application(_ application: UIApplication, handleActionWithIdentifier identifier: String?, for notification: UILocalNotification, withResponseInfo responseInfo: [AnyHashable : Any], completionHandler: @escaping () -> Void) {
print("new")
print(identifier,responseInfo)
completionHandler()
}
远程推送
什么是远程推送通知
- 顾名思义,就是从远程服务器推送给客户端的通知(需要联网)
- 远程推送服务,又称为APNs(Apple Push Notification Services
为什么需要远程推送通知?
传统获取数据的局限性
只要用户关闭了app,就无法跟app的服务器沟通,无法从服务器上获得最新的数据内容
不管用户打开还是关闭app,只要联网了,都能接收到服务器推送的远程通知
所有的苹果设备,在联网状态下,都会与苹果的服务器建立长连接
什么是长连接
只要联网了,就一直建立连接长连接的作用
时间校准
系统升级
查找我的iPhone
.. ...长连接的好处
数据传输速度快
数据保持最新状态
获取deviceToken
苹果需要用户的UDID和bundleID
qq案例分析
app 发送设备的UDID和
应用的Bundle Identifier
给APNs服务器经苹果加密生成一个
deviceToken 返还给当前appapp发送当前用户的deviceToken
和用户的标志(比如id或者qq) 给qq服务器qq服务器将用户的deviceToken存进数据库
当有人发送消息 李四的手机(昵称:李四 QQ:56789)
发给张三(QQ12345):吃饭没?消息先到qq服务器,然后去数据库查询张三的deviceToken
qq服务器通知苹果服务器
deviceTokoen:888
body:李四:吃饭没?苹果服务器通过deviceToken找到张三现在的设备
一.开发iOS程序的推送功能, iOS端需要做的事
1.请求苹果获得deviceToken
2.得到苹果返回的deviceToken,发送deviceToken给公司的服务器
- 监听用户对通知的点击
二.调试iOS的远程推送功能, 必备条件:
1.真机
2.调试推送需要的证书文件
1> aps_development.cer : 某台电脑就能调试某个app的推送服务
2> iphone5_qq.mobileprovision : 某台电脑就能利用某台设备调试某个程序
三.发布具有推送服务的app
1> aps_production.cer : 如果发布的程序中包含了推送服务,就必须安装这个证书
2> qq.mobileprovision : 某台电脑就能发布某个程序
制作证书
注册远程推送通知
客户端如果想接收APNs的远程推送通知,必须先注册(得到用户的授权)
一般在App启动完毕后就马上注册
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// 注册远程通知
UIRemoteNotificationType type = UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound;
[application registerForRemoteNotificationTypes:type];
return YES;
}
- 注册成功后会调用AppDelegate的下面方法,得到设备的deviceToken
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
NSLog(@"%@", deviceToken);
}
点击远程推送通知
当用户点击远程推送通知,会自动打开app,这里有2种情况
app并没有关闭,一直隐藏在后台
让app进入前台,并会调用AppDelegate的下面方法(并非重新启动app)
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo;
app已经被关闭(进程已死)
启动app,启动完毕会调用AppDelegate的下面方法
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;
launchOptions参数通过UIApplicationLaunchOptionsRemoteNotificationKey取出服务器返回的字典内容