系统卷更改观察器未在 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;
}

有两点需要注意:

  1. iOS15(至少在 beta2 中)的这个通知即使你按一次音量按钮也会被调用两次,但它们的 SequenceNumber 是相等的;
  2. 此通知回调不在主线程上。

尝试过 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”即可。