如題:要想達(dá)到微信收到語音震鈴效果需要用到UNNotificationServiceExtension,關(guān)于UNNotificationServiceExtension的使用可以參考iOS 10通知擴(kuò)展-通知服務(wù)擴(kuò)展這篇文章。
整體流程圖如下:

圖片.png
知識點
UNNotificationServiceExtension、App Groups、UNUserNotificationCenter
代碼實現(xiàn)
整體代碼
- (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];
// 結(jié)束定時器
[self endVibrationTimer];
[self removeAllNotification];
self.bestAttemptContent.body = [NSString stringWithFormat:@"%@,請盡快打開APP接聽!", self.bestAttemptContent.body];
self.contentHandler(self.bestAttemptContent);
});
// 持續(xù)震動
[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];
// 結(jié)束響鈴
AudioServicesDisposeSystemSoundID(soundID);
// 結(jié)束定時器
[self endVibrationTimer];
[self removeAllNotification];
self.contentHandler(self.bestAttemptContent);
}
});
dispatch_resume(self.vibrationTimer);
}
創(chuàng)建本地推送
/// 創(chuàng)建本地推送
- (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,是否重復(fù),如果重復(fù)的話時間必須大于60s,要不會報錯
UNTimeIntervalNotificationTrigger *trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:time repeats:NO];
// 添加通知的標(biāo)識符,可以用于移除,更新等操作
NSString *identifier = @"noticeId";
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:identifier content:content trigger:trigger];
[center addNotificationRequest:request withCompletionHandler:^(NSError *_Nullable error) {
NSLog(@"成功添加推送");
}];
}
}
這里的isForegroundIncoming方法涉及到Extension和主項目數(shù)據(jù)通信,這里使用到了App Groups 。具體可參考ios UNNotificationServiceExtension app和extension的通信這篇文章。