我在下面附上了一个完全可用的 SwiftUI 应用程序。例如,当我在后台播放 Apple Music 并转到应用程序并按下播放按钮时,我注意到每次都有大约 700 到 800 毫秒的挂起时间。没有收到 Apple 对此的答复。
我希望该应用程序能够接管其他应用程序的音乐。我不希望该应用程序的音频与其他应用程序混合。
struct ContentView: View {
@EnvironmentObject var contentViewModel: ContentViewModel
var body: some View {
Button {
AudioManager.shared.play()
} label: {
Image(systemName: contentViewModel.isPlaying ? "pause.fill" : "play.fill")
.font(.title)
.foregroundStyle(.white)
}
}
}
class ContentViewModel: ObservableObject {
@Published var isPlaying = false
}
class AudioManager {
static let shared = AudioManager()
private let audioEngine = AVAudioEngine()
private let playerNode = AVAudioPlayerNode()
let contentViewModel = ContentViewModel()
init() {
startAudioSession()
setupAudioEngine()
setupNotifications()
}
func startAudioSession() {
let session = AVAudioSession.sharedInstance()
do {
try session.setCategory(.playback)
try session.setActive(true)
} catch {
print("Failed to start Audio Session: \(error.localizedDescription)")
}
}
func setupAudioEngine() {
///Pass in a music file to the url here
let url = Bundle.main.url(forResource: "Your song goes here", withExtension: "mp3")!
do {
let audioFile = try AVAudioFile(forReading: url)
audioEngine.attach(playerNode)
audioEngine.connect(playerNode, to: audioEngine.mainMixerNode, format: audioFile.processingFormat)
playerNode.scheduleFile(audioFile, at: nil, completionCallbackType: .dataPlayedBack) {_ in
print("Song finished playing")
}
} catch let error {
print(error.localizedDescription)
}
}
func play() {
if playerNode.isPlaying {
playerNode.pause()
audioEngine.pause()
contentViewModel.isPlaying = false
} else {
do {
try audioEngine.start()
playerNode.play()
contentViewModel.isPlaying = true
} catch {
print(error.localizedDescription)
}
}
}
//Handling interruptions
func setupNotifications() {
let nc = NotificationCenter.default
nc.addObserver(self,
selector: #selector(handleInterruption),
name: AVAudioSession.interruptionNotification,
object: AVAudioSession.sharedInstance())
}
@objc func handleInterruption(notification: Notification) {
guard let userInfo = notification.userInfo,
let typeValue = userInfo[AVAudioSessionInterruptionTypeKey] as? UInt,
let type = AVAudioSession.InterruptionType(rawValue: typeValue) else {
return
}
// Switch over the interruption type.
switch type {
case .began:
// An interruption began. Update the UI as necessary.
print("Interruption Began")
play()
case .ended:
// An interruption ended. Resume playback, if appropriate.
guard let optionsValue = userInfo[AVAudioSessionInterruptionOptionKey] as? UInt else { return }
let options = AVAudioSession.InterruptionOptions(rawValue: optionsValue)
if options.contains(.shouldResume) {
// An interruption ended. Resume playback.
play()
} else {
// An interruption ended. Don't resume playback.
}
default: ()
}
}
}
我没有得到您的确切要求,但是,以下可以提高您的代码的性能。 AudioManager 的共享对象仅在您按下播放按钮时初始化。尝试在onAppear中初始化它并调用audioEngine.prepare().
extension AudioManager {
func prepareAudioEngine() {
audioEngine.prepare()
}
}
在onAppear
中调用该函数.onAppear(perform: {
AudioManager.shared.prepareAudioEngine()
})