iOS Theos Tweak中AVAudioSession中断后播放异常求助
问题:来电中断后音频播放器重启仅播放0.3秒即被停用
我用Theos为iOS应用编写Tweak,通过后台播放静音WAV文件延长后台生命周期。但来电会中断音频播放,我编写了AVAudioSessionInterruptionNotification的处理逻辑后,播放器虽能重启,但仅播放约0.3秒就被停用。我添加了大量日志仍未定位原因,作为Tweak开发新手,希望解决该问题,同时了解可用的调试工具。怀疑应用内存在其他中断通知处理器,想要找出是谁停用了音频播放器,进而通过Hook或其他方式规避。
相关代码
// Register interruption handler [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(audioSessionInterruption:) name:AVAudioSessionInterruptionNotification object:nil]; - (void)audioSessionInterruption:(NSNotification *)notification{ NSNumber *interruptionType = [[notification userInfo] objectForKey:AVAudioSessionInterruptionTypeKey]; NSNumber *interruptionOption = [[notification userInfo] objectForKey:AVAudioSessionInterruptionOptionKey]; switch (interruptionType.unsignedIntegerValue) { case AVAudioSessionInterruptionTypeBegan:{ NSLog(@"AVAudioSessionInterruptionTypeBegan"); } break; case AVAudioSessionInterruptionTypeEnded:{ if (interruptionOption.unsignedIntegerValue == AVAudioSessionInterruptionOptionShouldResume) { // Here should continue playback. Active audio session and play // Unfortunately, the audio player playing less one second, and be deactived by something NSLog(@"AVAudioSessionInterruptionTypeEnded"); [[AVAudioSession sharedInstance] setActive:YES error:nil]; [self.audioPlayer play]; } } break; default: break; } }
日志信息
CAReportingClient.mm:508 message {API = "[AVAudioSession etActive:activate]"; ElapsedTime = "6.517041";}: (176093659500) CAReportingClient.mm:508 message {API = "-[AVAudioSession ategory]"; ElapsedTime = "0.158375";}: (176093659500) CAReportingClient.mm:508 message {API = "-[AVAudioSession privateSetCategoryWithOptions:modes:routeSharingPolicy:options:]"; ElapsedTime = "5.618958";}: (176093659500) AVAudioSession_iOS.mm:1271 Deactivating an audio session that has running I/O. All I/O should be stopped or paused prior to deactivating the audio session. CAReportingClient.mm:508 message {API = "[AVAudioSession setActive:deactivate]"; ElapsedTime = "656.548541";}: (176093659500)
问题排查与解决方案
1. 定位停用音频会话的调用方
用Theos的Logos语法HookAVAudioSession的setActive:error:方法,打印调用栈找出是谁触发了停用操作:
%hook AVAudioSession - (BOOL)setActive:(BOOL)active error:(NSError **)error { BOOL result = %orig; if (!active) { NSLog(@"=== AVAudioSession setActive:NO 调用栈 ==="); NSLog(@"%@", [NSThread callStackSymbols]); } return result; } %end
2. 检查应用内的其他中断通知观察者
HookNSNotificationCenter的添加观察者方法,捕获所有监听AVAudioSessionInterruptionNotification的对象,确认是否有其他处理器干扰:
%hook NSNotificationCenter - (void)addObserver:(id)observer selector:(SEL)aSelector name:(NSNotificationName)aName object:(id)anObject { if ([aName isEqualToString:AVAudioSessionInterruptionNotification]) { NSLog(@"=== 新增AVAudioSession中断通知观察者:%@,方法:%@ ===", observer, NSStringFromSelector(aSelector)); } %orig; } %end
3. 修正音频会话激活逻辑
在恢复播放时不要忽略激活错误,同时确保播放器状态正常:
case AVAudioSessionInterruptionTypeEnded:{ if (interruptionOption.unsignedIntegerValue == AVAudioSessionInterruptionOptionShouldResume) { NSLog(@"AVAudioSessionInterruptionTypeEnded"); NSError *error = nil; BOOL activateSuccess = [[AVAudioSession sharedInstance] setActive:YES error:&error]; if (!activateSuccess) { NSLog(@"激活音频会话失败:%@", error); } if (!self.audioPlayer.isPlaying && self.audioPlayer.readyToPlay) { [self.audioPlayer play]; } } } break;
常用调试工具
- Console.app/系统日志:用Mac的Console.app查看应用日志,或在终端执行
log show --predicate 'process == "你的应用名"' --info过滤目标应用日志。 - LLDB调试:通过Theos的
debugserver连接设备,在LLDB中给AVAudioSession setActive:error:设置断点,实时查看调用栈。 - Cycript:注入到应用进程后,执行
[[NSNotificationCenter defaultCenter] observersForName:@"AVAudioSessionInterruptionNotification" object:nil]直接查看所有中断通知观察者。 - Logos Hook:利用Theos的Logos语法快速Hook任意方法,打印参数、返回值和调用栈。
内容的提问来源于stack exchange,提问作者ARD7N
相关产品推荐
相关产品推荐

