iOS 推送 长响铃 长震动 撤回推送消息的实现 详解
1 推送注册( ios10之后 )
float IOS_VERSION = [[[UIDevice currentDevice]systemVersion] floatValue];
if(IOS_VERSION >=10.0)
{
UNUserNotificationCenter * center = [UNUserNotificationCenter currentNotificationCenter];
[centersetDelegate:self];
UNAuthorizationOptions type = UNAuthorizationOptionBadge|UNAuthorizationOptionSound|UNAuthorizationOptionAlert;
[centerrequestAuthorizationWithOptions:type completionHandler:^(BOOL granted, NSError * _Nullable error)
{
if(granted){
dispatch_async(dispatch_get_main_queue(), ^{
[application registerForRemoteNotifications];
});
}
}];
}
2 获取token 以及上传后台
- (void)application:(UIApplication*)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
//APNS
NSMutableString*deviceTokenString = [NSMutableStringstring];
constchar*bytes = deviceToken.bytes;
NSIntegeriCount = deviceToken.length;
for(NSIntegeri =0; i < iCount; i++) {
[deviceTokenStringappendFormat:@"%02x", bytes[i]&0x000000FF];
}
self.apnsTokenStr= deviceTokenString;
[self uploadAPNSToken];
}
3 配置推送(原生APNS需要后台配合)
3.1 "sound": "ring.mp3”,
3.1.1 如果需要推送消息长响铃本地项目需要准备小于30秒的音频 推送字段和本地资源文件一致
3.1.2 如果有的消息不需要长响铃 则可以准备短的音频 字段一致即可
3.2 "mutable-content": 1,
3.2.1 如果为1 则表示可以被UNNotificationServiceExtension 拦截 在扩展的次方法 去配置需要显示的推送信息 (可以去根据需要去修改 title subtitle 等等)
- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request
withContentHandler:(void(^)(UNNotificationContent*_Nonnull))contentHandler
3.2.2 如果是0 则表示不会被拦截
3.3 "content-available": 0
3.3.1 如果是0 则表示不激活app 1 则表示收到推送的时候激活app
3.4 实现长响铃长震动 (千万不要在扩展里面 长响铃因为长响铃播放后不能自己控制停止当推送自动收回到通知栏后 响铃会一直响 怎么样都不能停止 直到响完为止)
3.4.1 长响铃已经在上面(3.1)说过 配置资源文件即可
3.4.2 长震动则需要在扩展实现
实现长震动
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
self.vibrationTimer=dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER,0,0, queue);
dispatch_source_set_timer(self.vibrationTimer, dispatch_walltime(NULL, 0), 1 * NSEC_PER_SEC, 0);
__block int times =0;
//启动定时器
dispatch_source_set_event_handler(self.vibrationTimer, ^{
self.contentHandler(self.bestAttemptContent);
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
times++;
if(times >=20|| isStateActive ){
//超过20次或点击推送,则停止震动
AudioServicesDisposeSystemSoundID(kSystemSoundID_Vibrate);
AudioServicesRemoveSystemSoundCompletion(kSystemSoundID_Vibrate);
dispatch_source_cancel(self.vibrationTimer);
}
});
dispatch_resume(self.vibrationTimer);
如果需要在 点击app进入或者点击推送 进入app和撤回消息的时候停止震动
则需要配合 app group NSUserDefaults (配置过程就不列举 网上资料很多) 去设置字段去控制 震动的停止 同时也需要再进入后台的时候 和杀死app的时候 去还原 为NO(根据业务去配置)
NSUserDefaults *userDefault = [[NSUserDefaults alloc]initWithSuiteName:@"app_group_push"];
[userDefaultsetObject:@(YES)forKey:@"app_group_stateActive"];
[userDefaultsynchronize];
3.5 apns-collapse-id
3.5.1 如果推送消息有 覆盖 或者撤回的需求 则需要后台在推送消息的时候在head 加入此 字段 需要注意的是 推送 被覆盖的推送和覆盖消息的推送 的apns-collapse-id 需要完全一 致 在覆盖推送消息的时候 如果上一条是 长响铃 则需要 先清除上一条 否则会出现两个都 响的问题 同时也需要停止长震动 (3.4已经补充) 代码如下
NSString*notify_id = [userInfo objectForKey:@"notify_id"];
if(notify_id) {
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
[center removeDeliveredNotificationsWithIdentifiers:@[notify_id]];
}
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.contentHandler(self.bestAttemptContent);
});
3.6 如果app收到推送 冷启动的时候进入app后获取不到推送信息的方案
3.6.1 如果content-available 为1 则app 在收到推送的时候会走此方法去处理收到推送的业务
- (void)application:(UIApplication*)applicationdidReceiveRemoteNotification: (NSDictionary*)userInfofetchCompletionHandler:(void(^) (UIBackgroundFetchResultresult))completionHandler
3.6.2 如果为0 则不会走此方法 则需要在扩展存储推送消息在进入app的时候 去获取存入的信息 (用完后需要清理 防止多次处理) 代码如下
NSUserDefaults*userDefault = [[NSUserDefaultsalloc]initWithSuiteName:@"app_group_push"];
[userDefaultsetObject:userInfo ? :@{}forKey:@"app_pushInfo"];
[userDefaultsynchronize];
//移除
[userDefault removeObjectForKey:@“app_pushInfo”];