我有TableViewController和AudioPlayerViewController。我在使用MPRemoteCommandCenter时遇到了问题。例如:在TableViewController中,我点击手机,然后进入AudioPlayerViewController,下一步我锁定设备,然后用MPRemoteCommandCenter控制我的音乐--一切正常。但是,如果我进一步解锁设备,返回到TableViewController,再次转到AudioPlayerViewController锁定设备,并按下播放/暂停按钮,我的音乐将同时播放两次。如果我重复这个动作,我的音乐将同时播放三次。等等..。如何修复它?
代码:
import UIKit
import AVFoundation
import MediaPlayer
class ViewController: UIViewController, AVAudioPlayerDelegate, UIAlertViewDelegate {
var audioPlayer: AVAudioPlayer!
let musicOperation = OperationQueue()
var timer: Timer?
@IBOutlet weak var playButton: UIButton!
@IBOutlet var timeElapsed: UILabel!
@IBOutlet var timeDuration: UILabel!
@IBOutlet weak var logo: UIImageView!
@IBOutlet weak var slider: UISlider!
@IBOutlet weak var volumeView: UIView!
var index = 0
var buttonIndex = 0
var endOfChapterSleepTimer = false
override func viewDidLoad() {
super.viewDidLoad()
// Table View Index
buttonIndex = masterIndex
musicOperation.maxConcurrentOperationCount = 1
try? AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
UserDefaults.standard.set(index, forKey: "index")
if index > 0 {
let fileManager = FileManager.default
let urls = fileManager.urls(for: .documentDirectory, in: .userDomainMask)
if let documentDirectoryURL: NSURL = urls.first as NSURL? {
let soundURL = documentDirectoryURL.appendingPathComponent("/\(masterIndex)/\(index).mp3")
UserDefaults.standard.set(index, forKey: "\(masterIndex)")
do {
audioPlayer = try AVAudioPlayer(contentsOf: soundURL!)
audioPlayer.delegate = self
audioPlayer.prepareToPlay()
play(sender:AnyObject.self as AnyObject)
restorePlayerCurrentTime()
setupMediaPlayerNotificationView()
lockScreen()
} catch {
}
}
} else {
let url = Bundle.main.url(forResource: "\(masterIndex)0", withExtension: "m4a")!
do {
audioPlayer = try AVAudioPlayer(contentsOf: url)
audioPlayer.delegate = self
audioPlayer.prepareToPlay()
play(sender:AnyObject.self as AnyObject)
setupMediaPlayerNotificationView()
lockScreen()
} catch {
}
}
}
// MARK: - Audio player controller
@IBAction func play(sender: AnyObject) {
if !audioPlayer.isPlaying{
audioPlayer.play()
slider.maximumValue = Float(audioPlayer.duration)
timer = Timer(timeInterval: 0.1, target: self, selector: #selector(self.updateTime), userInfo: nil, repeats: true)
RunLoop.main.add(timer!, forMode: .commonModes)
restorePlayerCurrentTime()
playButton.setImage(UIImage(named: "pause.png"), for: UIControlState.normal)
} else {
audioPlayer.pause()
playButton.setImage(UIImage(named: "play.png"), for: UIControlState.normal)
timer?.invalidate()
}
}
@IBAction func fastForward(sender: AnyObject) {
var time: TimeInterval = audioPlayer.currentTime
time += 15.0 // Go Forward by 15 Seconds
if time > audioPlayer.duration {
audioPlayerDidFinishPlaying(audioPlayer, successfully: true)
} else {
audioPlayer.currentTime = time
updateTime()
}
}
@IBAction func fastBackward(sender: AnyObject) {
var time: TimeInterval = audioPlayer.currentTime
time -= 15.0 // Go Back by 15 Seconds
if time < 0 {
audioPlayer.currentTime = 0
updateTime()
} else {
audioPlayer.currentTime = time
updateTime()
}
}
// MARK: - Audio player time
private func restorePlayerCurrentTime() {
let currentTimeFromUserDefaults : Double? = UserDefaults.standard.value(forKey: "currentTime\(masterIndex)\(index)") as! Double?
if let currentTimeFromUserDefaultsValue = currentTimeFromUserDefaults {
audioPlayer.currentTime = currentTimeFromUserDefaultsValue
slider.value = Float.init(audioPlayer.currentTime)
}
}
@objc func updateTime() {
let currentTime = Int(audioPlayer.currentTime)
let minutes = currentTime/60
let seconds = currentTime - minutes * 60
let durationTime = Int(audioPlayer.duration) - Int(audioPlayer.currentTime)
let minutes1 = durationTime/60
let seconds1 = durationTime - minutes1 * 60
timeElapsed.text = NSString(format: "%02d:%02d", minutes,seconds) as String
timeDuration.text = NSString(format: "-%02d:%02d", minutes1,seconds1) as String
UserDefaults.standard.set(currentTime, forKey: "currentTime\(masterIndex)\(index)")
UserDefaults.standard.set(durationTime, forKey: "durationTime\(masterIndex)\(index)")
slider.value = Float.init(audioPlayer.currentTime)
}
func audioPlayerDidFinishPlaying(_ audioPlayer: AVAudioPlayer, successfully flag: Bool) {
playButton.setImage(UIImage(named: "play.png"), for: UIControlState.normal)
let currentTime = 0
let durationTime = 0.1
UserDefaults.standard.set(currentTime, forKey: "currentTime\(masterIndex)\(index)")
UserDefaults.standard.set(durationTime, forKey: "durationTime\(masterIndex)\(index)")
slider.value = Float.init(audioPlayer.currentTime)
timer?.invalidate()
let path = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)
let documentDirectoryPath:String = path[0]
let fileManager = FileManager()
let destinationURLForFile = URL(fileURLWithPath: documentDirectoryPath.appendingFormat("/\(masterIndex)/\(index+1).mp3"))
if fileManager.fileExists(atPath: destinationURLForFile.path){
index = index + 1
viewDidLoad()
} else {
}
}
// MARK: - Audio player lock screen
func lockScreen() {
var albumArtwork : MPMediaItemArtwork!
let image:UIImage = UIImage(named: "infoImage")!
albumArtwork = MPMediaItemArtwork.init(boundsSize: image.size, requestHandler: { (size) -> UIImage in
return image
})
let infotitle = "title"
MPNowPlayingInfoCenter.default().nowPlayingInfo = [
MPMediaItemPropertyArtist : "",
MPMediaItemPropertyTitle : infotitle,
MPMediaItemPropertyArtwork : albumArtwork,
MPMediaItemPropertyAlbumTitle : "",
MPNowPlayingInfoPropertyElapsedPlaybackTime : Int(audioPlayer.currentTime),
MPMediaItemPropertyPlaybackDuration: Int(audioPlayer.duration)]
}
func setupMediaPlayerNotificationView() {
let commandCenter = MPRemoteCommandCenter.shared()
commandCenter.playCommand.addTarget { event in
self.audioPlayer.play()
self.lockScreen()
self.playButton.setImage(UIImage(named: "pause.png"), for: UIControlState.normal)
print("play")
return .success
}
commandCenter.pauseCommand.addTarget { event in
self.audioPlayer.pause()
self.lockScreen()
self.playButton.setImage(UIImage(named: "play.png"), for: UIControlState.normal)
print("pause")
return .success
}
commandCenter.skipBackwardCommand.preferredIntervals = [15]
commandCenter.skipBackwardCommand.addTarget { event in
self.fastBackward(sender: self)
self.lockScreen()
print("fastBackward")
return .success
}
commandCenter.skipForwardCommand.preferredIntervals = [15]
commandCenter.skipForwardCommand.addTarget { event in
self.fastForward(sender: self)
self.lockScreen()
print("fastForward")
return .success
}
commandCenter.changePlaybackPositionCommand.addTarget(self, action: #selector(self.changedThumbSlider(_:)))
@objc func changedThumbSlider(_ event: MPChangePlaybackPositionCommandEvent) -> MPRemoteCommandHandlerStatus {
let time = event.positionTime
audioPlayer.currentTime = TimeInterval(time)
self.lockScreen()
return .success
}
// MARK: - Audio player slider
@IBAction func slide(_ slider: UISlider) {
musicOperation.cancelAllOperations()
let operation = BlockOperation()
audioPlayer.currentTime = TimeInterval(slider.value)
self.lockScreen()
musicOperation.addOperation(operation)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
audioPlayer.pause()
timer?.invalidate()
musicOperation.cancelAllOperations()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
UIView.setAnimationsEnabled(true)
// Navigation Bar
self.navigationController?.navigationBar.prefersLargeTitles = true
self.navigationItem.largeTitleDisplayMode = .always
self.navigationController?.navigationBar.shadowImage = UIImage()
self.navigationController?.navigationBar.barTintColor = UIColor(red: 55/255, green: 60/255, blue: 65/255, alpha: 1.0)
self.navigationController?.navigationBar.isTranslucent = true
self.navigationController?.navigationBar.tintColor = .white
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}发布于 2021-06-01 16:38:34
发生的情况是,每次您转到AudioPlayerViewController时都会启用MPRemoteCommandCenter,但是当您返回到TableViewController时,您不会调用removeTarget。这是你的问题。
在viewWillDisappear to removeTarget中调用类似下面的内容
func setupMediaPlayerNotificationView(_ enable: Bool) {
let commandCenter = MPRemoteCommandCenter.shared()
if enable {
commandCenter.playCommand.addTarget(self, action: #selector(self.lockScreenPlay(_:)))
commandCenter.pauseCommand.addTarget(self, action: #selector(self.lockScreenPlay(_:)))
commandCenter.nextTrackCommand.addTarget(self, action: #selector(self.lockScreenNextTrack(_:)))
commandCenter.previousTrackCommand.addTarget(self, action: #selector(self.lockScreenPreviousTrack(_:)))
} else {
commandCenter.playCommand.removeTarget(self, action: #selector(self.lockScreenPlay(_:)))
commandCenter.pauseCommand.removeTarget(self, action: #selector(self.lockScreenPlay(_:)))
commandCenter.nextTrackCommand.removeTarget(self, action: #selector(self.lockScreenNextTrack(_:)))
commandCenter.previousTrackCommand.removeTarget(self, action: #selector(self.lockScreenPreviousTrack(_:)))
}
}后续问题示例:
@objc func lockScreenPlay(_ event: MPRemoteCommandEvent) -> MPRemoteCommandHandlerStatus {
self.playButton(AnyObject.self)
return .success
}
@objc func lockScreenNextTrack(_ event: MPRemoteCommandEvent) -> MPRemoteCommandHandlerStatus {
self.playerDidFinishPlaying()
return .success
}https://stackoverflow.com/questions/67785052
复制相似问题