I am having difficulty with my music app. I have posted on SO and Reddit numerous times.
The goal of the app is to play music and when you land on a song you like tap a button and play more songs from the artist that is currently playing. When I am IN the app and I hit next song it works fine. However if I let the song end naturally the app would play a random song. So I added logic to say if the songs remaining time is 0 then play next song using media players func because I know that works. This solved it except if the app is in the background. I tried to keep the app alive if it is in the background but I guess that is not working.
Every time I think I have solved something it the issue comes back.
**What I expect to happen** is lock on an Artist, close app to background and when the song ends play another song from Artist.
**What actually happens** is when I lock the artist and close app to background is the song will end and sometimes it will play the right song. Sometimes it will not. **HOWEVER** when it plays the wrong song and I open the app back up it ends the currently (Wrong) playing song and starts playing a song by the proper artist
I have set the Capabilities to background fetch and Audio Airplay and picture in picture
I have tried to only post relevant code in order..
I have a property
let mediaPlayer = MPMusicPlayerController.systemMusicPlayer
var backgroundTask: UIBackgroundTaskIdentifier = UIBackgroundTaskInvalid
In my **ViewDidLoad**
try? AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategorySoloAmbient)
try? AVAudioSession.sharedInstance().setActive(true)
DispatchQueue.main.async {
self.clearSongInfo()
MediaManager.shared.getAllSongs { (songs) in
guard let theSongs = songs else {
return
}
self.mediaPlayer.nowPlayingItem = nil
self.newSongs = theSongs.filter({ (item) -> Bool in
return !MediaManager.shared.playedSongs.contains(item)
})
self.aSongIsInChamber = true
self.mediaPlayer.setQueue(with: MPMediaItemCollection(items: self.newSongs.shuffled())
)
self.mediaPlayer.shuffleMode = .off
self.mediaPlayer.repeatMode = .none
}
NotificationCenter.default.addObserver(self, selector: #selector(self.songChanged(_:)), name: NSNotification.Name.MPMusicPlayerControllerNowPlayingItemDidChange, object: self.mediaPlayer)
self.mediaPlayer.beginGeneratingPlaybackNotifications()
}
I have a func that updates the played time and remaining time and in that I have
if Int(self.songProgressSlider.maximumValue - self.songProgressSlider.value) < 1 {
print("song ended naturally, skipped")
mediaPlayer.prepareToPlay(completionHandler: { (error) in
DispatchQueue.main.async {
self.mediaPlayer.skipToNextItem()
}
})
}
When I play the music I have a bool **isPlaying**
If it is then the time is running and I have this
let app = UIApplication.shared
var task: UIBackgroundTaskIdentifier?
task = app.beginBackgroundTask {
app.endBackgroundTask(task!)
}
I have that to keep the timer on in the background so it will play the next song when the time remaining is 0
Now to lock onto an Artist I have the following code that executes on button tap
let artistPredicate: MPMediaPropertyPredicate = MPMediaPropertyPredicate(value: nowPlaying.artist, forProperty: MPMediaItemPropertyArtist)
let query: MPMediaQuery = MPMediaQuery.artists()
let musicPlayerController: MPMusicPlayerController = MPMusicPlayerController.systemMusicPlayer
query.addFilterPredicate(artistPredicate)
musicPlayerController.setQueue(with: query)