Just as it has done for images with the UIImagePickerController
class and for email with the MFMailComposeViewController class , Apple has provided a standard way
to select and play back iPod media inside your own application.
Warning:
The MPMediaPickerController
and associated classes make use of the iPod library; this is not present
in iPhone Simulator and will work correctly only on the device
itself.
However, things are a little bit more complicated than the two
previous cases; here we use an MPMediaPickerController that, via the MPMediaPickerControllerDelegate
protocol, returns an MPMediaItemCollection
object containing the media items the user has selected, and
that can be played using an MPMusicPlayerController object.
These classes are provided by the Media Player framework; if you want to use them, you must
add the Media Player framework to your project by right-clicking the
Frameworks group in Groups & Files and selecting Add→Existing Frameworks.
Let’s reuse the Prototype application. Open the Finder and navigate
to the location where you saved the Prototype
project. Right-click on the folder containing the project files and select
Duplicate; a folder called Prototype copy will be
created containing a duplicate of the project.
Note:
To prune the Prototype application down to the stub, you will need
to:
Delete the WebViewController.h,
WebViewController.m, and
WebView.xib files from your project.
Remove the #import
"WebViewController.h" line from
PrototypeViewController.m.
Delete the current body of the pushedGo: method.
Next, open the PrototypeViewController.h
interface file, import the Media Player framework into the interface
(.h) files, and declare your class as an MPMediaPickerControllerDelegate:
#import <UIKit/UIKit.h>
#import <MediaPlayer/MediaPlayer.h>
@interface PrototypeViewController : UIViewController
<MPMediaPickerControllerDelegate> {
IBOutlet UIButton *goButton;
}
-(IBAction) pushedGo:(id)sender;
@end
Save your changes, and open the
PrototypeViewController.m implementation file. In the
pushedGo: method,
instantiate an MPMediaPickerController
object and present its view modally to the user:
-(IBAction) pushedGo:(id)sender {
MPMediaPickerController *mediaPicker =
[[MPMediaPickerController alloc]
initWithMediaTypes: MPMediaTypeAnyAudio];
mediaPicker.delegate = self;
mediaPicker.allowsPickingMultipleItems = YES;
[self presentModalViewController:mediaPicker animated:YES];
[mediaPicker release];
}
Now implement the following two delegate methods:
- (void) mediaPicker:(MPMediaPickerController *) mediaPicker
didPickMediaItems:(MPMediaItemCollection *) userMediaItemCollection
{
[self dismissModalViewControllerAnimated: YES];
MPMusicPlayerController *musicPlayer =
[MPMusicPlayerController applicationMusicPlayer];
[musicPlayer setQueueWithItemCollection: userMediaItemCollection];
[musicPlayer play];
}
- (void) mediaPickerDidCancel: (MPMediaPickerController *) mediaPicker {
[self dismissModalViewControllerAnimated: YES];
}
Save your changes, and click on the Build and Run button in the
Xcode toolbar to build and deploy your code. Remember that you’ll need to
configure your project to allow you to deploy the application
onto your iPhone or iPod touch so that you can test the application on
your device.
Once your application loads, tap the Go! button to bring up the
MPMediaPickerController,
select some songs, and tap the Done button in the navigation bar (see
Figure 1). Your music
should start playing.
Once playback has begun, you need to keep track of the currently
playing item and display that to the user, or at the very least provide
some way for the user to pause (or stop) playback, or perhaps to change
her selection. The MPMusicPlayerController class provides two
methods: the beginGeneratingPlaybackNotifications: method and
a corresponding endGeneratingPlaybackNotifications: method. Add
this line to the didPickMediaItems: method:
- (void) mediaPicker:(MPMediaPickerController *) mediaPicker
didPickMediaItems:(MPMediaItemCollection *) userMediaItemCollection {
[self dismissModalViewControllerAnimated: YES];
MPMusicPlayerController *musicPlayer =
[MPMusicPlayerController applicationMusicPlayer];
[musicPlayer setQueueWithItemCollection: userMediaItemCollection];
[musicPlayer beginGeneratingPlaybackNotifications];
[musicPlayer play];
}
When the begin method is invoked,
the class will start to generate notifications of when the player state
changes and when the current playback item changes, which your application can register to handle by adding
itself as an observer using the NSNotificationCenter class:
- (void) mediaPicker:(MPMediaPickerController *) mediaPicker
didPickMediaItems:(MPMediaItemCollection *) userMediaItemCollection {
[self dismissModalViewControllerAnimated: YES];
MPMusicPlayerController *musicPlayer =
[MPMusicPlayerController applicationMusicPlayer];
[musicPlayer setQueueWithItemCollection: userMediaItemCollection];
[musicPlayer beginGeneratingPlaybackNotifications];
NSNotificationCenter *notificationCenter =
[NSNotificationCenter defaultCenter];
[notificationCenter addObserver:self
selector:@selector(handleNowPlayingItemChanged:)
name:@"MPMusicPlayerControllerNowPlayingItemDidChangeNotification"
object:musicPlayer];
[notificationCenter addObserver:self
selector:@selector(handlePlaybackStateChanged:)
name:@"MPMusicPlayerControllerPlaybackStateDidChangeNotification"
object:musicPlayer];
[musicPlayer play];
}
This will invoke the selector methods in our class when the
appropriate notification arrives. (You could, for example, use the first
to update a UILabel in your view
telling the user the name of the currently playing song.)
However, for now let’s just implement these methods to print
messages to the console log. In the
PrototypeViewController.h interface file, declare the
selector methods:
@interface PrototypeViewController : UIViewController
<MPMediaPickerControllerDelegate>
{
IBOutlet UIButton *goButton;
}
-(IBAction) pushedGo:(id)sender;
- (void)handleNowPlayingItemChanged:(id)notification;
- (void)handlePlaybackStateChanged:(id)notification;
@end
Then, in the PrototypeViewController.m
implementation file, add the following method. This will be called when
the current item being played changes:
- (void)handleNowPlayingItemChanged:(id)notification {
MPMusicPlayerController *musicPlayer =
[MPMusicPlayerController applicationMusicPlayer];
MPMediaItem *currentItem = [musicPlayer nowPlayingItem];
NSLog(@"%@", currentItem);
}
While the second method handles changes in state, we can use this to
update our user interface (e.g., changing the state of the Play and Stop
buttons when the music ends):
- (void)handlePlaybackStateChanged:(id)notification {
MPMusicPlayerController *musicPlayer =
[MPMusicPlayerController applicationMusicPlayer];
MPMusicPlaybackState playbackState = [musicPlayer playbackState];
if (playbackState == MPMusicPlaybackStatePaused) {
NSLog(@"Paused");
} else if (playbackState == MPMusicPlaybackStatePlaying) {
NSLog(@"Playing");
} else if (playbackState == MPMusicPlaybackStateStopped) {
NSLog(@"Stopped");
}
}
Save your changes, and click on the Build and Run button in the
Xcode toolbar to build and deploy your code onto your device. Once your
application loads, tap the Go! button to bring up the MPMediaPickerController again, select some
songs, and tap the Done button in the navigation bar. Your music should
start playing, but this time you should see something similar to the
following log messages in the Debugger Console:
2009-12-11 00:29:42.535 Prototype[447:207] <MPMediaItem 0x1373e0>
persistentID: 6817778870160863775
2009-12-11 00:29:42.685 Prototype[447:207] Playing