iOS Applications that play audio in background mode, can be controlled from remote control commands inside command center or the lock screen of device.
We will need to import MediaPlayer initially.
import MediaPlayer
And also player in our UIViewController subclass
var player: AVPlayer?
We will need setup function which can enable/disable remote commands
func setupRemoteCommandCenter(enable: Bool) { let remoteCommandCenter = MPRemoteCommandCenter.shared() if enable { remoteCommandCenter.pauseCommand.addTarget(self, action: #selector(remoteCommandCenterPauseCommandHandler)) remoteCommandCenter.playCommand.addTarget(self, action: #selector(remoteCommandCenterPlayCommandHandler)) remoteCommandCenter.stopCommand.addTarget(self, action: #selector(remoteCommandCenterStopCommandHandler)) remoteCommandCenter.togglePlayPauseCommand.addTarget(self, action: #selector(remoteCommandCenterPlayPauseCommandHandler)) } else { remoteCommandCenter.pauseCommand.removeTarget(self, action: #selector(remoteCommandCenterPauseCommandHandler)) remoteCommandCenter.playCommand.removeTarget(self, action: #selector(remoteCommandCenterPlayCommandHandler)) remoteCommandCenter.stopCommand.removeTarget(self, action: #selector(remoteCommandCenterStopCommandHandler)) remoteCommandCenter.togglePlayPauseCommand.removeTarget(self, action: #selector(remoteCommandCenterPlayPauseCommandHandler)) } remoteCommandCenter.pauseCommand.isEnabled = enable remoteCommandCenter.playCommand.isEnabled = enable remoteCommandCenter.stopCommand.isEnabled = enable remoteCommandCenter.togglePlayPauseCommand.isEnabled = enable }
This function will be called with true to enable
setupRemoteCommandCenter(enable: true)
And should be called with false in deinit to stop handling remote commands
deinit { setupRemoteCommandCenter(enable: false) }
And the actual function selectors to handle remote commands
func remoteCommandCenterPauseCommandHandler() { // handle pause player?.pause() } func remoteCommandCenterPlayCommandHandler() { // handle play player?.play() } func remoteCommandCenterStopCommandHandler() { // handle stop player?.pause() } func remoteCommandCenterPlayPauseCommandHandler() { // handle play pause if player?.rate == 0.0 { player?.play() } else { player?.pause() } }
We will need setup player function
func setupPlayer() { let streamURL = URL(string: "https://audio.stream.m3u8")! self.player = AVPlayer(url: streamURL) self.player?.play() }
And in our example, we have a button selector function to call necessary code
@IBAction func playButtonHandler(btn: UIButton) { setupRemoteCommandCenter(enable: true) setupPlayer() }
Here is gist for the example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// https://hashaam.com/2017/07/19/handle-remote-control-commands/ | |
import UIKit | |
import MediaPlayer | |
class ViewController: UIViewController { | |
var player: AVPlayer? | |
func setupRemoteCommandCenter(enable: Bool) { | |
let remoteCommandCenter = MPRemoteCommandCenter.shared() | |
if enable { | |
remoteCommandCenter.pauseCommand.addTarget(self, action: #selector(remoteCommandCenterPauseCommandHandler)) | |
remoteCommandCenter.playCommand.addTarget(self, action: #selector(remoteCommandCenterPlayCommandHandler)) | |
remoteCommandCenter.stopCommand.addTarget(self, action: #selector(remoteCommandCenterStopCommandHandler)) | |
remoteCommandCenter.togglePlayPauseCommand.addTarget(self, action: #selector(remoteCommandCenterPlayPauseCommandHandler)) | |
} else { | |
remoteCommandCenter.pauseCommand.removeTarget(self, action: #selector(remoteCommandCenterPauseCommandHandler)) | |
remoteCommandCenter.playCommand.removeTarget(self, action: #selector(remoteCommandCenterPlayCommandHandler)) | |
remoteCommandCenter.stopCommand.removeTarget(self, action: #selector(remoteCommandCenterStopCommandHandler)) | |
remoteCommandCenter.togglePlayPauseCommand.removeTarget(self, action: #selector(remoteCommandCenterPlayPauseCommandHandler)) | |
} | |
remoteCommandCenter.pauseCommand.isEnabled = enable | |
remoteCommandCenter.playCommand.isEnabled = enable | |
remoteCommandCenter.stopCommand.isEnabled = enable | |
remoteCommandCenter.togglePlayPauseCommand.isEnabled = enable | |
} | |
deinit { | |
setupRemoteCommandCenter(enable: false) | |
} | |
func remoteCommandCenterPauseCommandHandler() { | |
// handle pause | |
player?.pause() | |
} | |
func remoteCommandCenterPlayCommandHandler() { | |
// handle play | |
player?.play() | |
} | |
func remoteCommandCenterStopCommandHandler() { | |
// handle stop | |
player?.pause() | |
} | |
func remoteCommandCenterPlayPauseCommandHandler() { | |
// handle play pause | |
if player?.rate == 0.0 { | |
player?.play() | |
} else { | |
player?.pause() | |
} | |
} | |
func setupPlayer() { | |
let streamURL = URL(string: "https://audio.stream.m3u8")! | |
self.player = AVPlayer(url: streamURL) | |
self.player?.play() | |
} | |
@IBAction func playButtonHandler(btn: UIButton) { | |
setupRemoteCommandCenter(enable: true) | |
setupPlayer() | |
} | |
} |
Helped me isolate a problem I was having with my code which used MPRemoteCommandCenter. Turns out the problem was not in the handler code itself, which building a project from your straightforward code above showed me. Many thanks!
LikeLike
Appreciate the feedback. Glad to help. By the way, I have started my youtube channel to cover complete in-depth series to develop apps.
LikeLike
Thanks for this! I had buggy Now Playing lockscreen controls and your post helped me sort out my issues. I also like how you implemented a Boolean argument for enabling/disabling MPRemoteCommandCenter; I never thought about doing that but that’s exactly what I needed to do.
LikeLike
Glad you found this helpful.
LikeLike