AVSystemController_SystemVolumeDidChangeNotification 设备锁定时触发
AVSystemController_SystemVolumeDidChangeNotification triggers when device locked
使用 iOS 12,我正在观察 AVSystemController_SystemVolumeDidChangeNotification
检测音量按下以捕获图像:
let volumeView = MPVolumeView(frame: CGRect(x: 0, y: -40, width: 0, height: 0)) // override volume view
view.addSubview(volumeView)
NotificationCenter.default.addObserver(self, selector: #selector(captureImage), name: Notification.Name(rawValue: "AVSystemController_SystemVolumeDidChangeNotification"), object: nil)
但是,我注意到当按下锁定按钮(位于设备右侧)时,至少在 iPhone XS 和 XS Max 上也会触发通知。
尝试四处搜索,但没有看到有人提到这个问题或对此通知进行过多讨论。其他类似的尝试使用 AVAudionSessions / KVO 来听音量按钮按下,但我发现每当我使用时,当音量已经达到 max/min 时,观察者不会被调用。这个 AVSystemController_SystemVolumeDidChangeNotification
似乎工作得很好,除了这个奇怪的锁定按钮问题。从通知的名称看不出它为什么会响应按下锁定按钮。
当按下锁定按钮时,我在控制台中收到以下消息:
[avas] AVAudioSessionPortImpl.mm:56:ValidateRequiredFields: Unknown selected data source for Port Speaker (type: Speaker) // this appears four times
+[CATransaction synchronize] called within transaction // this appears twice
按下音量按钮时不会出现这些日志。
另请注意,我不打算提交 App Store,所以我不担心 Apple 是否会以使用此可能是私人通知为由拒绝该应用程序。
如果我创建一个 AVAudioSession
而不是 AVSystemController_SystemVolumeDidChangeNotification
并像这样观察 outputVolume
:
let audioSession = AVAudioSession()
try? audioSession.setActive(true)
audioSession.addObserver(self, forKeyPath: "outputVolume", options: NSKeyValueObservingOptions.new, context: nil)
… 然后当设备锁定时它不会被击中,但我仍然看到“AVAudioSessionPortImpl.mm 端口扬声器的未知选定数据源”控制台错误。但是当音量被静音时,它不再接受按压。我想我需要做的是手动更改音量,以免达到最小值或最大值?
谢谢
最后手动保持音量不变并使用音频会话方法。不得不投入一些技巧。这有点令人费解,所以我愿意接受更清洁的替代方案。不知道 Apple 会对在应用程序中提交此消息有何反应,尽管他们似乎肯定接受使用音量按钮与相机交互的应用程序。
在 UIViewController 子类中:
override func viewDidLoad() {
super.viewDidLoad()
// …
setupVolumeButton()
}
private let volumeView = MPVolumeView(frame: CGRect(x: 0, y: -100, width: 0, height: 0)) // override volume view
private func setupVolumeButton() {
view.addSubview(volumeView)
setVolume(0.5) { // in case app launches with volume at max/min already
// need to wait until initial volume setting is done
// so it doesn't get triggered on launch
let audioSession = AVAudioSession()
try? audioSession.setActive(true)
audioSession.addObserver(self, forKeyPath: "outputVolume", options: NSKeyValueObservingOptions.new, context: nil)
}
}
private func setVolume(_ volume: Float, completion: (() -> Void)? = nil) {
let slider = volumeView.subviews.first(where: { [=10=] is UISlider }) as? UISlider
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1) {
slider?.value = volume
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.01) {
// needed to wait a bit before completing so the observer doesn't pick up the manualq volume change
completion?()
}
}
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if keyPath == "outputVolume" {
setVolume(0.5) // keep from reaching max or min volume so button keeps working
doTheThingThatShouldHappenWhenTheVolumeButtonIsPressed()
}
}
编辑:我还注意到当应用程序关闭时音频会话被停用,所以我将音频会话存储在 属性 中,添加了一个观察者以观察应用程序何时再次激活,并在关联的方法我将音频会话设置为再次激活。
使用 iOS 12,我正在观察 AVSystemController_SystemVolumeDidChangeNotification
检测音量按下以捕获图像:
let volumeView = MPVolumeView(frame: CGRect(x: 0, y: -40, width: 0, height: 0)) // override volume view
view.addSubview(volumeView)
NotificationCenter.default.addObserver(self, selector: #selector(captureImage), name: Notification.Name(rawValue: "AVSystemController_SystemVolumeDidChangeNotification"), object: nil)
但是,我注意到当按下锁定按钮(位于设备右侧)时,至少在 iPhone XS 和 XS Max 上也会触发通知。
尝试四处搜索,但没有看到有人提到这个问题或对此通知进行过多讨论。其他类似的尝试使用 AVAudionSessions / KVO 来听音量按钮按下,但我发现每当我使用时,当音量已经达到 max/min 时,观察者不会被调用。这个 AVSystemController_SystemVolumeDidChangeNotification
似乎工作得很好,除了这个奇怪的锁定按钮问题。从通知的名称看不出它为什么会响应按下锁定按钮。
当按下锁定按钮时,我在控制台中收到以下消息:
[avas] AVAudioSessionPortImpl.mm:56:ValidateRequiredFields: Unknown selected data source for Port Speaker (type: Speaker) // this appears four times
+[CATransaction synchronize] called within transaction // this appears twice
按下音量按钮时不会出现这些日志。
另请注意,我不打算提交 App Store,所以我不担心 Apple 是否会以使用此可能是私人通知为由拒绝该应用程序。
如果我创建一个 AVAudioSession
而不是 AVSystemController_SystemVolumeDidChangeNotification
并像这样观察 outputVolume
:
let audioSession = AVAudioSession()
try? audioSession.setActive(true)
audioSession.addObserver(self, forKeyPath: "outputVolume", options: NSKeyValueObservingOptions.new, context: nil)
… 然后当设备锁定时它不会被击中,但我仍然看到“AVAudioSessionPortImpl.mm 端口扬声器的未知选定数据源”控制台错误。但是当音量被静音时,它不再接受按压。我想我需要做的是手动更改音量,以免达到最小值或最大值?
谢谢
最后手动保持音量不变并使用音频会话方法。不得不投入一些技巧。这有点令人费解,所以我愿意接受更清洁的替代方案。不知道 Apple 会对在应用程序中提交此消息有何反应,尽管他们似乎肯定接受使用音量按钮与相机交互的应用程序。
在 UIViewController 子类中:
override func viewDidLoad() {
super.viewDidLoad()
// …
setupVolumeButton()
}
private let volumeView = MPVolumeView(frame: CGRect(x: 0, y: -100, width: 0, height: 0)) // override volume view
private func setupVolumeButton() {
view.addSubview(volumeView)
setVolume(0.5) { // in case app launches with volume at max/min already
// need to wait until initial volume setting is done
// so it doesn't get triggered on launch
let audioSession = AVAudioSession()
try? audioSession.setActive(true)
audioSession.addObserver(self, forKeyPath: "outputVolume", options: NSKeyValueObservingOptions.new, context: nil)
}
}
private func setVolume(_ volume: Float, completion: (() -> Void)? = nil) {
let slider = volumeView.subviews.first(where: { [=10=] is UISlider }) as? UISlider
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1) {
slider?.value = volume
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.01) {
// needed to wait a bit before completing so the observer doesn't pick up the manualq volume change
completion?()
}
}
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if keyPath == "outputVolume" {
setVolume(0.5) // keep from reaching max or min volume so button keeps working
doTheThingThatShouldHappenWhenTheVolumeButtonIsPressed()
}
}
编辑:我还注意到当应用程序关闭时音频会话被停用,所以我将音频会话存储在 属性 中,添加了一个观察者以观察应用程序何时再次激活,并在关联的方法我将音频会话设置为再次激活。