如何使用 MPMediaPickerController 选择的歌曲在 Swift 中播放背景音乐?
How to play music in background in Swift with MPMediaPickerController chosen songs?
我试图让用户从他们的音乐库中挑选一首歌曲并在不同的视图控制器上播放。我目前可以选择歌曲并播放它们,但我不知道如何在后台播放它们。谢谢!
class ViewController: UIViewController,
MPMediaPickerControllerDelegate, AVAudioPlayerDelegate {
var myMusicPlayer: MPMusicPlayerController?
var mediaPicker: MPMediaPickerController?
var backgroundMusicPlayer:AVAudioPlayer = AVAudioPlayer()
@IBAction func musicBtn(sender: AnyObject) {
displayMediaPickerAndPlayItem()
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
func musicPlayerStateChanged(notification: NSNotification){
print("Player State Changed")
/* Let's get the state of the player */
let stateAsObject =
notification.userInfo!["MPMusicPlayerControllerPlaybackStateKey"]
as? NSNumber
if let state = stateAsObject{
/* Make your decision based on the state of the player */
switch MPMusicPlaybackState(rawValue: state.integerValue)!{
case .Stopped:
/* Here the media player has stopped playing the queue. */
print("Stopped")
case .Playing:
/* The media player is playing the queue. Perhaps you
can reduce some processing that your application
that is using to give more processing power
to the media player */
print("Paused")
case .Paused:
/* The media playback is paused here. You might want
to indicate by showing graphics to the user */
print("Paused")
case .Interrupted:
/* An interruption stopped the playback of the media queue */
print("Interrupted")
case .SeekingForward:
/* The user is seeking forward in the queue */
print("Seeking Forward")
case .SeekingBackward:
/* The user is seeking backward in the queue */
print("Seeking Backward")
}
}
}
func nowPlayingItemIsChanged(notification: NSNotification){
print("Playing Item Is Changed")
let key = "MPMusicPlayerControllerNowPlayingItemPersistentIDKey"
let persistentID =
notification.userInfo![key] as? NSString
if let id = persistentID{
/* Do something with Persistent ID */
print("Persistent ID = \(id)")
}
}
func volumeIsChanged(notification: NSNotification){
print("Volume Is Changed")
/* The userInfo dictionary of this notification is normally empty */
}
func mediaPicker(mediaPicker: MPMediaPickerController,
didPickMediaItems mediaItemCollection: MPMediaItemCollection){
print("Media Picker returned")
/* Instantiate the music player */
myMusicPlayer = MPMusicPlayerController()
if let player = myMusicPlayer{
player.beginGeneratingPlaybackNotifications()
/* Get notified when the state of the playback changes */
NSNotificationCenter.defaultCenter().addObserver(self,
selector: "musicPlayerStateChanged:",
name: MPMusicPlayerControllerPlaybackStateDidChangeNotification,
object: nil)
/* Get notified when the playback moves from one item
to the other. In this recipe, we are only going to allow
our user to pick one music file */
NSNotificationCenter.defaultCenter().addObserver(self,
selector: "nowPlayingItemIsChanged:",
name: MPMusicPlayerControllerNowPlayingItemDidChangeNotification,
object: nil)
/* And also get notified when the volume of the
music player is changed */
NSNotificationCenter.defaultCenter().addObserver(self,
selector: "volumeIsChanged:",
name: MPMusicPlayerControllerVolumeDidChangeNotification,
object: nil)
/* Start playing the items in the collection */
player.setQueueWithItemCollection(mediaItemCollection)
player.play()
/* Finally dismiss the media picker controller */
mediaPicker.dismissViewControllerAnimated(true, completion: nil)
}
}
func mediaPickerDidCancel(mediaPicker: MPMediaPickerController) {
/* The media picker was cancelled */
print("Media Picker was cancelled")
mediaPicker.dismissViewControllerAnimated(true, completion: nil)
}
func stopPlayingAudio(){
NSNotificationCenter.defaultCenter().removeObserver(self)
if let player = myMusicPlayer{
player.stop()
}
}
func displayMediaPickerAndPlayItem(){
mediaPicker = MPMediaPickerController(mediaTypes: .AnyAudio)
if let picker = mediaPicker{
print("Successfully instantiated a media picker")
picker.delegate = self
picker.allowsPickingMultipleItems = true
picker.showsCloudItems = true
picker.prompt = "Pick a song please..."
view.addSubview(picker.view)
presentViewController(picker, animated: true, completion: nil)
} else {
print("Could not instantiate a media picker")
}
}
}
你可以使用单例来实现它:
import AVFoundation
class MusicHelper {
static let sharedHelper = MusicHelper()
var audioPlayer: AVAudioPlayer?
func playBackgroundMusic() {
let pickedSong = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("userPickedSong", ofType: "mp3")!)
do {
audioPlayer = try AVAudioPlayer(contentsOfURL:aSound)
audioPlayer!.numberOfLoops = -1
audioPlayer!.prepareToPlay()
audioPlayer!.play()
} catch {
print("Cannot play the file")
}
}
}
你可以这样使用它:
MusicHelper.sharedHelper.playBackgroundMusic()
这只是您如何做到这一点的一个例子。其实还有很多,Whosebug
上已经有答案了。但是按照我展示的方式,您可以在任何 class.
中调用它
如果你想播放 "across different view controllers" 那么不要将 AVAudioPlayer 放在 one 视图控制器中。如果你这样做,当你离开那个视图控制器时它会被销毁。
将音频播放器放在无论如何都能生存的地方,例如您的 App Delegate。
我试图让用户从他们的音乐库中挑选一首歌曲并在不同的视图控制器上播放。我目前可以选择歌曲并播放它们,但我不知道如何在后台播放它们。谢谢!
class ViewController: UIViewController,
MPMediaPickerControllerDelegate, AVAudioPlayerDelegate {
var myMusicPlayer: MPMusicPlayerController?
var mediaPicker: MPMediaPickerController?
var backgroundMusicPlayer:AVAudioPlayer = AVAudioPlayer()
@IBAction func musicBtn(sender: AnyObject) {
displayMediaPickerAndPlayItem()
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
func musicPlayerStateChanged(notification: NSNotification){
print("Player State Changed")
/* Let's get the state of the player */
let stateAsObject =
notification.userInfo!["MPMusicPlayerControllerPlaybackStateKey"]
as? NSNumber
if let state = stateAsObject{
/* Make your decision based on the state of the player */
switch MPMusicPlaybackState(rawValue: state.integerValue)!{
case .Stopped:
/* Here the media player has stopped playing the queue. */
print("Stopped")
case .Playing:
/* The media player is playing the queue. Perhaps you
can reduce some processing that your application
that is using to give more processing power
to the media player */
print("Paused")
case .Paused:
/* The media playback is paused here. You might want
to indicate by showing graphics to the user */
print("Paused")
case .Interrupted:
/* An interruption stopped the playback of the media queue */
print("Interrupted")
case .SeekingForward:
/* The user is seeking forward in the queue */
print("Seeking Forward")
case .SeekingBackward:
/* The user is seeking backward in the queue */
print("Seeking Backward")
}
}
}
func nowPlayingItemIsChanged(notification: NSNotification){
print("Playing Item Is Changed")
let key = "MPMusicPlayerControllerNowPlayingItemPersistentIDKey"
let persistentID =
notification.userInfo![key] as? NSString
if let id = persistentID{
/* Do something with Persistent ID */
print("Persistent ID = \(id)")
}
}
func volumeIsChanged(notification: NSNotification){
print("Volume Is Changed")
/* The userInfo dictionary of this notification is normally empty */
}
func mediaPicker(mediaPicker: MPMediaPickerController,
didPickMediaItems mediaItemCollection: MPMediaItemCollection){
print("Media Picker returned")
/* Instantiate the music player */
myMusicPlayer = MPMusicPlayerController()
if let player = myMusicPlayer{
player.beginGeneratingPlaybackNotifications()
/* Get notified when the state of the playback changes */
NSNotificationCenter.defaultCenter().addObserver(self,
selector: "musicPlayerStateChanged:",
name: MPMusicPlayerControllerPlaybackStateDidChangeNotification,
object: nil)
/* Get notified when the playback moves from one item
to the other. In this recipe, we are only going to allow
our user to pick one music file */
NSNotificationCenter.defaultCenter().addObserver(self,
selector: "nowPlayingItemIsChanged:",
name: MPMusicPlayerControllerNowPlayingItemDidChangeNotification,
object: nil)
/* And also get notified when the volume of the
music player is changed */
NSNotificationCenter.defaultCenter().addObserver(self,
selector: "volumeIsChanged:",
name: MPMusicPlayerControllerVolumeDidChangeNotification,
object: nil)
/* Start playing the items in the collection */
player.setQueueWithItemCollection(mediaItemCollection)
player.play()
/* Finally dismiss the media picker controller */
mediaPicker.dismissViewControllerAnimated(true, completion: nil)
}
}
func mediaPickerDidCancel(mediaPicker: MPMediaPickerController) {
/* The media picker was cancelled */
print("Media Picker was cancelled")
mediaPicker.dismissViewControllerAnimated(true, completion: nil)
}
func stopPlayingAudio(){
NSNotificationCenter.defaultCenter().removeObserver(self)
if let player = myMusicPlayer{
player.stop()
}
}
func displayMediaPickerAndPlayItem(){
mediaPicker = MPMediaPickerController(mediaTypes: .AnyAudio)
if let picker = mediaPicker{
print("Successfully instantiated a media picker")
picker.delegate = self
picker.allowsPickingMultipleItems = true
picker.showsCloudItems = true
picker.prompt = "Pick a song please..."
view.addSubview(picker.view)
presentViewController(picker, animated: true, completion: nil)
} else {
print("Could not instantiate a media picker")
}
}
}
你可以使用单例来实现它:
import AVFoundation
class MusicHelper {
static let sharedHelper = MusicHelper()
var audioPlayer: AVAudioPlayer?
func playBackgroundMusic() {
let pickedSong = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("userPickedSong", ofType: "mp3")!)
do {
audioPlayer = try AVAudioPlayer(contentsOfURL:aSound)
audioPlayer!.numberOfLoops = -1
audioPlayer!.prepareToPlay()
audioPlayer!.play()
} catch {
print("Cannot play the file")
}
}
}
你可以这样使用它:
MusicHelper.sharedHelper.playBackgroundMusic()
这只是您如何做到这一点的一个例子。其实还有很多,Whosebug
上已经有答案了。但是按照我展示的方式,您可以在任何 class.
如果你想播放 "across different view controllers" 那么不要将 AVAudioPlayer 放在 one 视图控制器中。如果你这样做,当你离开那个视图控制器时它会被销毁。
将音频播放器放在无论如何都能生存的地方,例如您的 App Delegate。