系统卷更改观察器未在 iOS 15 上工作
System Volume Change Observer not working on iOS 15
我使用以下代码来检测用户更改的系统音量。
NotificationCenter.default.addObserver(self, selector: #selector(volumeChanged), name: NSNotification.Name(rawValue: "AVSystemController_SystemVolumeDidChangeNotification"), object: nil)
当我更新到 iOS 15 时,我发现这段代码不起作用,但对于任何以前的 iOS 版本都可以。
我也用了一个addObserver
函数,不过没关系。
这是 iOS 15 错误吗?如果是,我该如何修复它。
谢谢:)
您正在做的事情不受支持,因此如果它不能在所有系统上运行也不足为奇。正确的记录方法是在音频会话中使用 KVO outputVolume
属性: https://developer.apple.com/documentation/avfaudio/avaudiosession/1616533-outputvolume
我迷上了 MPVolumeControllerSystemDataSource 的方法 _systemVolumeDidChange 并且在 iOS 15.0(至少 beta2) 通知名称已更改为 SystemVolumeDidChange,这是新的通知结构:
{
AudioCategory = "Audio/Video";
Reason = ExplicitVolumeChange;
SequenceNumber = 1069;
Volume = 0;
}
有两点需要注意:
- iOS15(至少在 beta2 中)的这个通知即使你按一次音量按钮也会被调用两次,但它们的 SequenceNumber 是相等的;
- 此通知回调不在主线程上。
尝试过 AdamWang 的回答后,我发现您需要创建并保留一个 MPVolumeView 实例(但不需要添加到您的视图层次结构中),否则将不会发出通知。
在 iOS15 中不再调用 @"AVSystemController_SystemVolumeDidChangeNotification" 通知。
改为使用键值观察。 (扩展上面马特的回答)
在您的 ViewController.m 文件中
#import <AVFoundation/AVFoundation.h>
#import <MediaPlayer/MediaPlayer.h>
@interface ViewController : UIViewController
{
AVAudioSession *audioSession;
}
@end
在您的视图中 Controller.m 文件
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
audioSession = [AVAudioSession sharedInstance];
[audioSession setActive:YES error:nil];
[audioSession addObserver:self forKeyPath:@"outputVolume" options:0 context:nil];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[audioSession removeObserver:self forKeyPath:@"outputVolume"];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
CGFloat newVolume = audioSession.outputVolume;
NSLog(@"newVolume: %f", newVolume);
//if the volume gets to max or min observer won't trigger
if (newVolume > 0.9 || newVolume < 0.1) {
[self setSystemVolume:0.5];
return;
}
}
//set the volume programatically
- (void)setSystemVolume:(CGFloat)volume {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
[[MPMusicPlayerController applicationMusicPlayer] setVolume:(float)volume];
#pragma clang diagnostic pop
}
您可以使用移出屏幕的 MPVolumeView 隐藏音量滑块。
Hide device Volume HUD view while adjusitng volume with MPVolumeView slider
如果有人突然不明白如何应用AdamWang的解决方案,你只需要将“AVSystemController_SystemVolumeDidChangeNotification
”替换为“SystemVolumeDidChange
”即可。
我使用以下代码来检测用户更改的系统音量。
NotificationCenter.default.addObserver(self, selector: #selector(volumeChanged), name: NSNotification.Name(rawValue: "AVSystemController_SystemVolumeDidChangeNotification"), object: nil)
当我更新到 iOS 15 时,我发现这段代码不起作用,但对于任何以前的 iOS 版本都可以。
我也用了一个addObserver
函数,不过没关系。
这是 iOS 15 错误吗?如果是,我该如何修复它。
谢谢:)
您正在做的事情不受支持,因此如果它不能在所有系统上运行也不足为奇。正确的记录方法是在音频会话中使用 KVO outputVolume
属性: https://developer.apple.com/documentation/avfaudio/avaudiosession/1616533-outputvolume
我迷上了 MPVolumeControllerSystemDataSource 的方法 _systemVolumeDidChange 并且在 iOS 15.0(至少 beta2) 通知名称已更改为 SystemVolumeDidChange,这是新的通知结构:
{
AudioCategory = "Audio/Video";
Reason = ExplicitVolumeChange;
SequenceNumber = 1069;
Volume = 0;
}
有两点需要注意:
- iOS15(至少在 beta2 中)的这个通知即使你按一次音量按钮也会被调用两次,但它们的 SequenceNumber 是相等的;
- 此通知回调不在主线程上。
尝试过 AdamWang 的回答后,我发现您需要创建并保留一个 MPVolumeView 实例(但不需要添加到您的视图层次结构中),否则将不会发出通知。
在 iOS15 中不再调用 @"AVSystemController_SystemVolumeDidChangeNotification" 通知。
改为使用键值观察。 (扩展上面马特的回答)
在您的 ViewController.m 文件中
#import <AVFoundation/AVFoundation.h>
#import <MediaPlayer/MediaPlayer.h>
@interface ViewController : UIViewController
{
AVAudioSession *audioSession;
}
@end
在您的视图中 Controller.m 文件
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
audioSession = [AVAudioSession sharedInstance];
[audioSession setActive:YES error:nil];
[audioSession addObserver:self forKeyPath:@"outputVolume" options:0 context:nil];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[audioSession removeObserver:self forKeyPath:@"outputVolume"];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
CGFloat newVolume = audioSession.outputVolume;
NSLog(@"newVolume: %f", newVolume);
//if the volume gets to max or min observer won't trigger
if (newVolume > 0.9 || newVolume < 0.1) {
[self setSystemVolume:0.5];
return;
}
}
//set the volume programatically
- (void)setSystemVolume:(CGFloat)volume {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
[[MPMusicPlayerController applicationMusicPlayer] setVolume:(float)volume];
#pragma clang diagnostic pop
}
您可以使用移出屏幕的 MPVolumeView 隐藏音量滑块。
Hide device Volume HUD view while adjusitng volume with MPVolumeView slider
如果有人突然不明白如何应用AdamWang的解决方案,你只需要将“AVSystemController_SystemVolumeDidChangeNotification
”替换为“SystemVolumeDidChange
”即可。