iOS应用中播放UNNotificationSound.default()及获取播放用户选择铃声的方法
嘿,我来帮你搞定这两个iOS音频相关的问题~这两个场景在很多社交、工具类APP里都很常见,我给你详细拆解一下具体实现方式:
UNNotificationSound的默认音效本质是系统自带的通知提示音,但它本身是为推送通知设计的,要在应用内直接播放,得先拿到它对应的音频文件URL,再用AVAudioPlayer或者AVPlayer来实现播放。这里给你用AVAudioPlayer的完整实现:
先配置音频权限
别忘了在Info.plist里添加NSAudioUsageDescription键,写上应用使用音频的原因(比如“用于播放通知提示音”),不然会触发权限错误甚至崩溃。获取默认音效的URL并播放
代码示例(Swift):import AVFoundation import UserNotifications func playDefaultNotificationSound() { // 配置音频会话,确保应用可以正常播放音频 do { try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default) try AVAudioSession.sharedInstance().activate(options: [.notifyOthersOnDeactivation]) } catch { print("音频会话配置失败: \(error.localizedDescription)") return } // 获取默认通知音效的URL guard let soundURL = UNNotificationSound.default().soundURL else { print("无法获取默认通知音效的URL") return } // 初始化播放器并播放 do { let player = try AVAudioPlayer(contentsOf: soundURL) player.prepareToPlay() // 提前加载音频,优化播放响应速度 player.play() } catch { print("播放器初始化失败: \(error.localizedDescription)") } }如果你需要更灵活的播放控制(比如暂停、进度条),也可以用
AVPlayer替代,用法类似,只是初始化方式改成AVPlayer(url: soundURL)后调用play()即可。
要做一个包含系统默认铃声的选择列表,你需要访问系统的音频资源目录,枚举其中的音频文件,再对选中的铃声做播放或文件名提取操作:
1. 先定义一个铃声模型(可选但推荐)
用一个简单的结构体来统一管理铃声的名称和URL,方便后续列表展示和操作:
struct Ringtone { let displayName: String // 给用户看的铃声名称(去掉后缀) let fileURL: URL // 铃声文件的本地路径 }
2. 枚举系统铃声目录,获取完整列表
系统铃声主要存在两个目录:通知铃声在/System/Library/Audio/UISounds/Notifications/,电话铃声在/System/Library/Audio/UISounds/Ringtones/。你可以根据需求选择枚举哪个目录:
import AVFoundation func fetchSystemRingtones() -> [Ringtone] { var ringtoneList = [Ringtone]() let supportedAudioExtensions = ["caf", "mp3", "m4a"] // iOS支持的音频格式 // 枚举指定目录下的音频文件 func scanRingtoneDirectory(at directoryURL: URL) { do { // 获取目录下所有可见文件 let fileURLs = try FileManager.default.contentsOfDirectory( at: directoryURL, includingPropertiesForKeys: nil, options: .skipsHiddenFiles ) for fileURL in fileURLs { // 过滤出支持的音频格式文件 guard let fileExt = fileURL.pathExtension.lowercased(), supportedAudioExtensions.contains(fileExt) else { continue } // 提取去掉后缀的文件名作为显示名称 let displayName = fileURL.deletingPathExtension().lastPathComponent ringtoneList.append(Ringtone(displayName: displayName, fileURL: fileURL)) } } catch { print("扫描铃声目录失败: \(error.localizedDescription)") } } // 扫描通知铃声和电话铃声目录 let notificationDirURL = URL(fileURLWithPath: "/System/Library/Audio/UISounds/Notifications/") let ringtoneDirURL = URL(fileURLWithPath: "/System/Library/Audio/UISounds/Ringtones/") scanRingtoneDirectory(at: notificationDirURL) scanRingtoneDirectory(at: ringtoneDirURL) return ringtoneList }
3. 播放用户选中的铃声
当用户从列表中选中某个铃声后,直接用AVAudioPlayer播放即可,逻辑和播放默认音效一致:
func playSelectedRingtone(_ ringtone: Ringtone) { do { try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default) try AVAudioSession.sharedInstance().activate() let player = try AVAudioPlayer(contentsOf: ringtone.fileURL) player.prepareToPlay() player.play() } catch { print("播放选中铃声失败: \(error.localizedDescription)") } }
4. 获取选中铃声的文件名
- 如果你要不带后缀的显示名称,直接取
ringtone.displayName即可; - 如果你要带后缀的完整文件名,可以用
ringtone.fileURL.lastPathComponent。
注意事项:
- iOS系统版本更新可能会微调铃声目录结构,建议在不同版本的设备上测试兼容性;
- 所有系统铃声的播放都是符合Apple开发者规范的,不用担心版权问题;
- 同样要确保
Info.plist中配置了NSAudioUsageDescription权限描述。
内容的提问来源于stack exchange,提问作者Melany

