###一 了解苹果推送 苹果推送分为本地推送、在线推送、离线推送三种模式, 本地推送是使用一套本地推送的机制和网络服务器无关,可用于闹钟之类的需求,在线推送是应用处于前台模式,使用APP自己的长链接推送 ,和APP设置通知的开关没有关系 ,离线推送就是APNs推送了,app服务器发送推送请求到APNs服务器,APNs服务器发送推送到指定的设备,离线推送就和APP设置的通知开关有关系了。以微信为例,当微信处于前台时是进入微信自己的长链接推送通道,和手机APP设置推送是否开启无关, 处于后台模式、锁屏或者kill了则使用APNs通道,通知关闭则收不到推送了 ####1 远程推送 远程推送又可以可以分为静默推送和正常推送 正常推送用户会收到推送内容、声音,应用处于后台或者kill点击推送内容进入APP后才会会进入
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
静默推送是一种特殊的远程推送,没有推送内容声音,不用点击推送内容也不用进入APP就会执行,用户毫无感觉
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
静默推送是iOS7.0之后推出的,又被称为:Background Remote Notification(后台远程推送)可以不用打开APP就可以运行代码,(大多是用户毫无察觉的处理 服务器传到APP的数据,更新APP内容) ####2本地推送 本地推送和远程推送一样都是通知APP做事情,远程推送是需要联网的,只有联网才能和苹果服务器APNs建立长链接、接受APNs的消息,本地推送是不需要联网的,APP内部实现推送功能,本地推送的目标是安装了APP的设备,受APP在该设备的通知是否开启影响。最常用的就是闹钟APP 注意:iOS8 - iOS10的本地推送:当应用处于前台是不会有横幅或者弹框,用户无感知,可以在didReceiveLocalNotification 回调中处理弹框使用户感知,让应用处于后台才会有横幅和弹框铃声等, 推送的注册和回调,64条是苹果官方设置的上限。
-(void)registerAPNs:(UIApplication *)application
{
// iOS8~iOS10 与 iOS10之后的系统本地推送是不同的
if (@available(iOS 10.0, *)) {
UNUserNotificationCenter *unCenter = [UNUserNotificationCenter currentNotificationCenter];
unCenter.delegate = self;
[unCenter requestAuthorizationWithOptions:(UNAuthorizationOptionAlert | UNAuthorizationOptionBadge | UNAuthorizationOptionSound) completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (!error) {
NSLog(@"注册成功");
dispatch_async(dispatch_get_main_queue(), ^{
[[UIApplication sharedApplication] registerForRemoteNotifications];
});
}
}];
[unCenter getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
NSLog(@"regist success settting is =====+%@",settings);
}];
} else {
if ([application respondsToSelector:@selector(registerUserNotificationSettings:)]) {
UIUserNotificationSettings *setttings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:nil];
[application registerUserNotificationSettings:setttings];
[application registerForRemoteNotifications];
}
}
}
#pragma mark -- ios10 推送代理
//不实现通知不会有提示
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler
API_AVAILABLE(ios(10.0)) API_AVAILABLE(ios(10.0)) API_AVAILABLE(ios(10.0)){
completionHandler(UNNotificationPresentationOptionBadge | UNNotificationPresentationOptionSound | UNNotificationPresentationOptionAlert);
}
//对通知响应
-(void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler
API_AVAILABLE(ios(10.0)) API_AVAILABLE(ios(10.0)){
if ([response.notification.request.content.categoryIdentifier isEqualToString:@"request1"]) {
[self handleResponse:response];
}
completionHandler();
}
//点击通知 进入APP的回调对通知响应
-(void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler
API_AVAILABLE(ios(10.0)) API_AVAILABLE(ios(10.0)){
NSString *categoryIdentifier = response.notification.request.content.categoryIdentifier;
if ([categoryIdentifier isEqualToString:@"categoryIdentifier"]) {
[self handleResponse:response];
}
completionHandler();
}
#pragma mark ---------------处理点击通知进入APP后的事件
-(void)handleResponse:(UNNotificationResponse *)response
API_AVAILABLE(ios(10.0)){
[UIApplication sharedApplication].applicationIconBadgeNumber = 0;
if ([response.actionIdentifier isEqualToString:@"commitActionTitle"])
{
NSLog(@"commit Action =====");
}else if ([response.actionIdentifier isEqualToString:@"textAction1"]){
UNTextInputNotificationResponse *textResponse = (UNTextInputNotificationResponse *)response;
NSString *userText = textResponse.userText;
NSLog(@"input text is ======%@",userText);
}else if ([response.actionIdentifier isEqualToString:@"cancelActionTitle"]){
NSLog(@"cancel Action -------");
}
NSLog(@"%@",@"处理通知");
}
设置推送内容 fireDate、timeZone、repeatInterval和repeatCalendar的含义 1 fireDate是UILocalNotification的激发的确切时间。 2 timeZone是UILocalNotification激发时间所根据的时区,如果设置为nil的话,那么UILocalNotification将在一段时候后被激发,而不是某一个确切时间被激发。 3 repeatInterval是UILocalNotification被重复激发之间的时间差,不过时间差是完全根据日历单位(NSCalendarUnit)的,例如每周激发的单位,NSWeekCalendarUnit,如果不设置的话,将不会重复激发。 4 repeatCalendar是UILocalNotification重复激发所使用的日历单位需要参考的日历,如果不设置的话,系统默认的日历将被作为参考日历。 5添加category按钮,和用户点击推送内容进行交互 UNTextInputNotificationAction:用户输入text,可以在didReceiveNotificationResponse回调中获取text内容 UNNotificationAction:根据需求自定义推送点击按钮
-(void)setLocalNotification
{
// 只创建一个通知,重复一次创建一次太恐怖了
NSArray *notificatinArr = [[UIApplication sharedApplication] scheduledLocalNotifications];
if (notificatinArr.count) {
return;
}
NSString *title = @"通知-title";
NSString *subTitle = @"通知-subTitle";
NSString *body = @"通知-body";
NSInteger badge = 1;
NSInteger timeIntevel = 60;
NSDictionary *userInfo = @{@"id":@"LOCAL_NOTIFY_SCHEDULE_ID"};
if (@available(iOS 10.0, *)) {
UNUserNotificationCenter *NotifCenter = [UNUserNotificationCenter currentNotificationCenter];
UNMutableNotificationContent *notificationContent = [[UNMutableNotificationContent alloc] init];
notificationContent.sound = [UNNotificationSound defaultSound];
notificationContent.title = title;
notificationContent.subtitle = subTitle;
notificationContent.body = body;
notificationContent.badge = @(badge);
notificationContent.userInfo = userInfo;
NSError *error = nil;
NSString *path = [[NSBundle mainBundle] pathForResource:@"jjy2" ofType:@"jpg"];
// 设置通知附件内容
UNNotificationAttachment *att = [UNNotificationAttachment attachmentWithIdentifier:@"att1" URL:[NSURL fileURLWithPath:path] options:nil error:&error];
notificationContent.attachments = @[att];
notificationContent.launchImageName = @"jjy2.png";
// 设置声音
UNNotificationSound *sound = [UNNotificationSound soundNamed:@"sound02.wav"]; //要有后缀
notificationContent.sound = sound;
// 标识符 推送用户的交互 左拉,点击管理按钮 会出现category 按钮
notificationContent.categoryIdentifier = @"categoryIdentifier";
UNTextInputNotificationAction *textAction = [UNTextInputNotificationAction actionWithIdentifier:@"textAction1" title:@"textActionTitle1" options:UNNotificationActionOptionForeground textInputButtonTitle:@"textInpuButtonTitle1" textInputPlaceholder:@"textInputPlaceholder1"];
UNNotificationAction *commitAction = [UNNotificationAction actionWithIdentifier:@"commitAction" title:@"commitActionTitle" options:UNNotificationActionOptionForeground];
UNNotificationAction *cancelAction = [UNNotificationAction actionWithIdentifier:@"cancelAction" title:@"cancelActionTitle" options:UNNotificationActionOptionForeground];
UNNotificationCategory *notifCategory = [UNNotificationCategory categoryWithIdentifier:@"categoryIdentifier" actions:@[textAction,commitAction,cancelAction] intentIdentifiers:@[] options:UNNotificationCategoryOptionNone];
NSSet *categorySet = [[NSSet alloc] initWithObjects:notifCategory, nil];
[NotifCenter setNotificationCategories:categorySet];
// 设置触发模式
UNTimeIntervalNotificationTrigger *timeIntervalTrigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:timeIntevel repeats:YES];
// 设置UNNotificationRequest
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:@"request1" content:notificationContent trigger:timeIntervalTrigger];
// 把通知加到UNUserNotificationCenter 到指定触发点会被触发
[NotifCenter addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
if (!error) {
NSLog(@"addNotificationRequest success :error is %@",error);
}
else{
NSLog(@"addNotificationRequest failed");
}
}];
if (error) {
NSLog(@"attachment error %@",error);
}
} else {
// iOS10之前的系统 APP处于后台才会有提示,但是会收到推送
UILocalNotification *localNotification = [[UILocalNotification alloc] init];
localNotification.alertTitle = [self setLowVersionLocalNotification:title];
localNotification.alertBody = [self setLowVersionLocalNotification:body];
localNotification.alertLaunchImage = [[NSBundle mainBundle] pathForResource:@"jjy2" ofType:@"jpg"];
// 锁屏状态下显示的文字
localNotification.alertAction = @"锁屏状态下";
localNotification.timeZone = [NSTimeZone defaultTimeZone];
localNotification.fireDate = [NSDate dateWithTimeIntervalSinceNow:1];
localNotification.repeatInterval = NSCalendarUnitMinute;
localNotification.soundName = @"sound01.wav";//UILocalNotificationDefaultSoundName;
localNotification.userInfo = @{@"keyInfo":@"valueInfo",
@"id" :@"LOCAL_NOTIFY_SCHEDULE_ID"};
localNotification.applicationIconBadgeNumber = 1;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
}
}
取消推送
//不重复推送:推送一次后就会自动取消推送,重复推送的话需要手动取消,不然即使卸载应用也会残留,下次重装也会继续推送
-(void)cancelLocalNotifications
{
NSArray *notificationArr = [[UIApplication sharedApplication] scheduledLocalNotifications];
if (!notificationArr || notificationArr.count <= 0) {
return;
}
for (UILocalNotification *localNotify in notificationArr) {
if ([[localNotify.userInfo valueForKey:@"id"] isEqualToString:@"LOCAL_NOTIFY_SCHEDULE_ID"]) {
if (@available(iOS 10.0, *)) {
[[UNUserNotificationCenter currentNotificationCenter] removePendingNotificationRequestsWithIdentifiers:@[@"request1"]];
} else {
[[UIApplication sharedApplication] cancelLocalNotification:localNotify];
}
}
}
}
###3远程推送 ######1 远程推送原理: 客户端注册远程推送发送Token key ,APNs服务器根据Token key 下发给客户端deviceToken; 客户端把DeviceToken发送给自己的服务器,自己的服务器发送推送消息给APNs服务器,APNs服务器将消息发给DeviceToken对应设备上的客户端,如下图所示

{
"aps" : {
"alert" : { // string or dictionary
"title" : "string"
"body" : "string",
"title-loc-key" : "string or null"
"title-loc-args" : "array of strings or null"
"action-loc-key" : "string or null"
"loc-key" : "string"
"loc-args" : "array of strings"
"launch-image" : "string"
},
"badge" : number,
"sound" : "string"
"content-available" : number;
"category" : "string"
},
}
aps:推送消息必须有的key alert:推送消息包含此key值,系统根据设备显示弹框 badge:在APP图标右上角显示的消息数目,缺少此key,消息数目不会改变,消除标记时把此key对应的value设置为0 sound:设置推送声音的key值,value 为default时会用系统默认的提示音 content-available:此key设置为1时,在收到消息之前会进入extent server 的回调方法,修改显示的值 category:UNNotificationCategory的identifier, 用户可操作的类型的key值 title:推送消息的标题:iOS8.2之后 body:推送内容 title-loc-key:功能类似title,附加功能是国际化,iOS8.2之后 title-loc-args:配合title-loc-key字段使用,iOS8.2之后 action-loc-key:可操作通知类型的key loc-key:参考title-loc-key loc-args:参考title-loc-args launch-image:点击推送消息或者移动时间滑块时显示的图片,如果缺少此key值,会加载App默认的启动图片 自定义ke值
{
"aps" : {
"alert" : "Provider push messag.",
"badge" : 9,
"sound" : "toAlice.aiff"
},
"Id" : 1314, // 自定义key值
"type" : "customType" // 自定义key值
}
1模拟器不能接受推送,没有deviceToken,必须真机
参考链接:www.jianshu.com/p/48c3d6eca… cloud.tencent.com/developer/a… www.cocoachina.com/ios/2016101… www.jianshu.com/p/78ef7bc04… www.jianshu.com/p/174b55d5e… 远程推送:blog.csdn.net/leiyutinghu…