iOS仿微信语音来电持续震铃
2023-07-31 本文已影响0人
落寞绅士
如题:要想达到微信收到语音震铃效果需要用到UNNotificationServiceExtension
,关于UNNotificationServiceExtension
的使用可以参考iOS 10通知扩展-通知服务扩展这篇文章。
整体流程图如下:
图片.png知识点
UNNotificationServiceExtension
、App Groups
、UNUserNotificationCenter
代码实现
整体代码
- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
self.contentHandler = contentHandler;
self.bestAttemptContent = [request.content mutableCopy];
NSDictionary *apns = self.bestAttemptContent.userInfo[@"aps"];
NSLog(@"didReceiveNotificationRequest:withContentHandler: -- apns = %@", apns);
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
NSString *sound = apns ? [apns objectForKey:@"sound"] : nil;
// 来电推送
if (sound && [sound isEqualToString:@"incoming.wav"]) {
// 删除推送本身的铃声
self.bestAttemptContent.sound = nil;
[self incomingNotification];
}
// 其他推送
else {
self.contentHandler(self.bestAttemptContent);
}
}
来电推送
/// 来电推送
- (void)incomingNotification
{
// 前台来电
if ([self isForegroundIncoming]) {
return;
}
[self addLocalNotice:self.bestAttemptContent.title body:self.bestAttemptContent.body];
// 播放声音
NSString *path = [[NSBundle mainBundle] pathForResource:@"incoming.wav" ofType:nil];
static SystemSoundID soundID = 0;
NSURL *filePath = [NSURL fileURLWithPath:path isDirectory:NO];
[[AVAudioSession sharedInstance] setActive:YES error:NULL];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:NULL];
AudioServicesCreateSystemSoundID((__bridge CFURLRef)filePath, &soundID);
AudioServicesPlayAlertSoundWithCompletion(soundID, ^{
NSLog(@"didReceiveNotificationRequest:withContentHandler: -- 播报完成");
[self setAppGroupsIncoming:NO];
// 结束定时器
[self endVibrationTimer];
[self removeAllNotification];
self.bestAttemptContent.body = [NSString stringWithFormat:@"%@,请尽快打开APP接听!", self.bestAttemptContent.body];
self.contentHandler(self.bestAttemptContent);
});
// 持续震动
[self destroyVibrationTimer];
self.vibrationTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC);
dispatch_source_set_timer(self.vibrationTimer, start, 1 * NSEC_PER_SEC, 0);
dispatch_source_set_event_handler(self.vibrationTimer, ^{
// 震动
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
// 是否前台来电
if ([self isForegroundIncoming]) {
[self setAppGroupsIncoming:NO];
// 结束响铃
AudioServicesDisposeSystemSoundID(soundID);
// 结束定时器
[self endVibrationTimer];
[self removeAllNotification];
self.contentHandler(self.bestAttemptContent);
}
});
dispatch_resume(self.vibrationTimer);
}
创建本地推送
/// 创建本地推送
- (void)addLocalNotice:(NSString *)title body:(NSString *)body
{
if (@available(iOS 10.0, *)) {
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
content.title = title;
content.body = body;
content.sound = nil;
content.badge = @1;
NSTimeInterval time = [[NSDate dateWithTimeIntervalSinceNow:1] timeIntervalSinceNow];
// repeats,是否重复,如果重复的话时间必须大于60s,要不会报错
UNTimeIntervalNotificationTrigger *trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:time repeats:NO];
// 添加通知的标识符,可以用于移除,更新等操作
NSString *identifier = @"noticeId";
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:identifier content:content trigger:trigger];
[center addNotificationRequest:request withCompletionHandler:^(NSError *_Nullable error) {
NSLog(@"成功添加推送");
}];
}
}
这里的isForegroundIncoming
方法涉及到Extension和主项目数据通信,这里使用到了App Groups
。具体可参考ios UNNotificationServiceExtension app和extension的通信这篇文章。