iOS仿微信语音来电持续震铃

2023-07-31  本文已影响0人  落寞绅士

如题:要想达到微信收到语音震铃效果需要用到UNNotificationServiceExtension,关于UNNotificationServiceExtension的使用可以参考iOS 10通知扩展-通知服务扩展这篇文章。

整体流程图如下:

图片.png

知识点

UNNotificationServiceExtensionApp GroupsUNUserNotificationCenter

代码实现

整体代码
- (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的通信这篇文章。

上一篇下一篇

猜你喜欢

热点阅读