Мое приложение представляет собой музыкальный проигрыватель, использующий AVAudioPlayer с одноцветным рисунком и фоновым режимом. Все идет хорошо, но после добавления командного центра для управления заблокированным экраном я обнаружил одно странное поведение.
Когда я использую кнопку паузы / воспроизведения на заблокированном экране, иногда это может создать дополнительный sharedInstance ofaudioPlay на фоне , потому что я нашел многократную дублирующую печать, например, в моем коде commandCenter.pauseCommand
. Аудио приостанавливается или возобновляет воспроизведение, но следующий щелчок по кнопке командного центра и по кнопке воспроизведения / паузы в ВК приложения не имеет никакого эффекта. Это многопоточная проблема, ну, я очень новичок в Swift, любая помощь или подсказка о том, как найти / решить эту проблему, приветствуется.
Обновление , один сценарий для повторения:
- Приостановка воспроизведения звука в приложении.
- Заблокируйте экран с помощью кнопки питания, затем снова откройте экран и нажмите кнопку воспроизведения на панели управления.
- Возобновление звукаДля воспроизведения на заблокированном экране и по истечении указанного времени продолжите обработку, затем снова откройте приложение, панель процессов по-прежнему останавливается на предыдущей позиции, и в следующий раз щелчок воспроизведения / паузы не действует.
/ / / кодкомандного центра и MPMediaItemProperty
func setUpLockedScreenControl() {
// add control panel on locked screen
let commandCenter = MPRemoteCommandCenter.shared()
commandCenter.pauseCommand.isEnabled = true
commandCenter.playCommand.isEnabled = true
commandCenter.nextTrackCommand.isEnabled = true
commandCenter.previousTrackCommand.isEnabled = true
commandCenter.pauseCommand.addTarget { (event) -> MPRemoteCommandHandlerStatus in
SongData.isPlaying = false
AudioManager.sharedInstance.pauseMusic()
self.updateLockedScreenPlayingInfo()
print("pause music in command center")
self.playOrPauseButton.setImage(UIImage(named: "Play"), for: .normal)
self.playOrPauseButton.imageView?.contentMode = .scaleAspectFit
return .success
}
commandCenter.playCommand.addTarget { (event) -> MPRemoteCommandHandlerStatus in
SongData.isPlaying = true
AudioManager.sharedInstance.playMusic()
self.updateLockedScreenPlayingInfo()
print("play music in command center")
// add to continue update playing progress
self.playOrPauseButton.setImage(UIImage(named: "Pause"), for: .normal)
self.playOrPauseButton.imageView?.contentMode = .scaleAspectFit
return .success
}
commandCenter.nextTrackCommand.addTarget { (event) -> MPRemoteCommandHandlerStatus in
self.goNextSong()
self.updateLockedScreenPlayingInfo()
return .success
}
commandCenter.previousTrackCommand.addTarget { (event) -> MPRemoteCommandHandlerStatus in
self.goPreviousSong()
self.updateLockedScreenPlayingInfo()
return .success
}
}
func updateLockedScreenPlayingInfo() {
var info = Dictionary<String, Any>()
info[MPMediaItemPropertyTitle] = SongData.songList[SongData.currentTrack].songName
info[MPMediaItemPropertyAlbumTitle] = SongData.songList[SongData.currentTrack].albumName
info[MPMediaItemPropertyArtist] = SongData.songList[SongData.currentTrack].artistName
let image = SongData.songList[SongData.currentTrack].albumArtwork
let artwork = MPMediaItemArtwork.init(boundsSize: image.size, requestHandler: { (size) -> UIImage in
return image
})
info[MPMediaItemPropertyArtwork] = artwork
info[MPMediaItemPropertyPlaybackDuration] = AudioManager.sharedInstance.audioPlayer.duration
if SongData.isPlaying == true {
let time = AudioManager.sharedInstance.audioPlayer.currentTime
info[MPNowPlayingInfoPropertyElapsedPlaybackTime] = time
info[MPMediaItemPropertyPlaybackDuration] = AudioManager.sharedInstance.audioPlayer.duration
info[MPNowPlayingInfoPropertyPlaybackRate] = 1.0
print("SongData.isPlaying == true, current time is:", time)
} else {
let time = AudioManager.sharedInstance.audioPlayer.currentTime
info[MPNowPlayingInfoPropertyElapsedPlaybackTime] = time
info[MPMediaItemPropertyPlaybackDuration] = AudioManager.sharedInstance.audioPlayer.duration
info[MPNowPlayingInfoPropertyPlaybackRate] = 0.0
print("SongData.isPlaying == false, current time is:", time)
}
MPNowPlayingInfoCenter.default().nowPlayingInfo = info
}
/ / / здесь информация о консоли, когда произошла ошибка, в этом случае дважды печатать commandCenter.playCommand
код
Playback OK
Session is Active
2019-10-23 11:38:06.331882+0800 LocalMusicPlayer[12366:853141] Can't end BackgroundTask: no background task exists with identifier 22 (0x16), or it may have already been ended. Break in UIApplicationEndBackgroundTaskError() to debug.
SongData.isPlaying == true, current time is: 5.15344671201814
play music in command center
SongData.isPlaying == true, current time is: 5.155759637188209
play music in command center
/ / / backgroundрежим установлен в appDelegate, а Can't end BackgroundTask
происходит только на iOS 13, я думаю, это может быть проблемой на стороне Apple.
func applicationWillResignActive(_ application: UIApplication) {
do {
// set options as empty [] could show control panel in locked screen.
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [])
print("Playback OK")
try AVAudioSession.sharedInstance().setActive(true)
print("Session is Active")
} catch {
print(error)
}
}
/ / / Audio Manager.swift для управления audioPlayer
class AudioManager: NSObject, AVAudioPlayerDelegate {
// use Singleton pattern keep the music continuing when user move through the App.
static let sharedInstance = AudioManager()
var audioPlayer: AVAudioPlayer!
var playingSong: SongData?
private override init() {
super.init()
}
... ...
}
/ / / Воспроизведение / Пауза в приложенияхВК
@IBAction func PlayOrPauseMusic(_ sender: UIButton) {
if SongData.isPlaying {
print("pause the music playing")
SongData.isPlaying = false
AudioManager.sharedInstance.pauseMusic()
updateLockedScreenPlayingInfo()
playOrPauseButton.setImage(UIImage(named: "Play"), for: .normal)
playOrPauseButton.imageView?.contentMode = .scaleAspectFit
} else {
print("continue to play current music")
SongData.isPlaying = true
AudioManager.sharedInstance.playMusic()
updateLockedScreenPlayingInfo()
playOrPauseButton.setImage(UIImage(named: "Pause"), for: .normal)
playOrPauseButton.imageView?.contentMode = .scaleAspectFit
}
}