项目需要监听当前iOS设备音量,当音量太小时给出提示,用户调整到合适音量后去掉提示。
一、旧方法 (iOS15后失效)
原理:通过监听苹果未公开的消息 AVSystemController_SystemVolumeDidChangeNotification
(1)在程序开始时监听
NotificationCenter.default.addObserver(self, selector: #selector(volumeDidChange(notification:)), name: NSNotification.Name(rawValue: "AVSystemController_SystemVolumeDidChangeNotification"), object: nil)
(2)监听回调
@objc func volumeDidChange(notification: NSNotification) {
let volume = notification.userInfo!["AVSystemController_AudioVolumeNotificationParameter"] as! Float
print(#line, "volumeDidChange", volume)
// 这里加入业务代码
}
(3)程序结束时记得移除监听
NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: "AVSystemController_SystemVolumeDidChangeNotification"), object: nil)
对于iOS15, 这里还有个变体。主要将消息从AVSystemController_SystemVolumeDidChangeNotification换成SystemVolumeDidChange stackoverflow.com/questions/6…
但是iOS16试了不起作用。
二、新方法 (亲测可用,推荐)
采用苹果公开的API AVAudioSession,但需要注意的是:这个方法只在真机有效,模拟器不起作用。
(1)实现一个监听封装类VolumeListener
import Foundation
import AVFoundation
class VolumeListener: NSObject {
private var audioSession: AVAudioSession!
private var volumeObservation: NSKeyValueObservation?
private var volumeDidChange: (_ volume:Float) -> () //音量变化通知函数
init(volumeDidChange: @escaping (_ volume:Float) -> ()) {
self.volumeDidChange = volumeDidChange
super.init()
setupAudioSession()
}
private func setupAudioSession() {
audioSession = AVAudioSession.sharedInstance()
do {
try audioSession.setActive(true, options: [])
} catch {
print("Failed to activate audio session: \(error)")
return
}
startObservingVolume()
}
private func startObservingVolume() {
volumeObservation = audioSession.observe(\.outputVolume, options: [.initial, .new]) { [weak self] (audioSession, _) in
let currentVolume = audioSession.outputVolume
self?.volumeDidChange(currentVolume)
}
}
// func volumeDidChange(volume: Float) {
// print("Volume did change: \(volume)")
// // 在此处执行音量更改后的操作
// }
func stopObservingVolume() {
volumeObservation = nil
}
deinit {
stopObservingVolume()
}
}
这个函数的options参数要注意 audioSession.observe(.outputVolume, options: [.initial, .new])
以下是 NSKeyValueObservingOptions 的一些常用选项:
.new:观察者将收到属性的新值。在回调方法中,可以通过 change[.newKey] 获取新值。
.old:观察者将收到属性的旧值。在回调方法中,可以通过 change[.oldKey] 获取旧值。
.initial:在添加观察者时立即触发回调,这样可以获取属性的当前值。通常与 .new 一起使用,以便在添加观察者时收到初始值。
.prior:在属性更改之前和之后触发回调。回调将被调用两次,其中一次是在属性值改变之前。
如果options为空,则只会在音量改变时回调。如果想在用户改变音量前就获取一次当前音量,则要在options中添加.initial。
(2)在需要使用的地方 先定义
private var volumeListener: VolumeListener? //音量大小变化监听
在ViewDidLoad里初始化
volumeListener = VolumeListener(volumeDidChange:volumeDidChange(_:))
实现监听代码
//这个在模拟器不行,只能在真机
func volumeDidChange(_ volume: Float){
print("volumeDidChange , volume: \(volume)")
//业务代码
}