You want to play music or just some audio content with a simple UI within your app? There were several libraries for doing that: MusicPlayerViewController, MDAudioPlayerController and many more. But none of them seem to be active any more. If you are starting development on an app that includes a music player, the best option is to write one from scratch. Its really easy too and you get to customize the player as you like which is great.
So let’s see what we need. Unless you want to deal directly with AV Foundation, I recommend using SoundManager which is a simple class for playing sound and music in iOS or Mac apps.
pod 'SoundManager', '~> 1.4'
Now, it’s time to design our UI. We will start with a very basic one with Play/Pause, Next, Prev and a Slider to control the music progress.
Setup View Controller
- (void)viewDidLoad {
[super viewDidLoad];
[self setupSoundManager];
[self updateViews];
}
- (void)setupSoundManager {
[[SoundManager sharedManager] prepareToPlay];
}
- (void)updateViews {
SDContent *currentContent = (SDContent *) self.content[(NSUInteger) self.index]
// Update image
[self.photoImageView setImage:currentContent.image];
// Update song name and artist
self.musicLabel.text = currentContent.title;
self.artistLabel.text = currentContent.artistName;
}
Start Playing
- (void)start {
[self updateViews];
[self beginPlaying];
}
- (void)beginPlaying {
NSString *resourceName = @"stairway-to-heaven.mp3";
self.sound = [Sound soundNamed:resourceName];
[[SoundManager sharedManager] playMusic:self.sound looping:NO fadeIn:NO];
// Update slider
self.progressSlider.minimumValue = 0;
self.progressSlider.maximumValue = (float) self.sound.duration;
// Update play button
self.playButton.selected = YES;
// Update duration
self.durationLabel.text = [self formatTimeSeconds:(int) self.sound.duration];
// Listen for play udpates
[self updateSoundProgress];
self.playUpdatesTimer = [NSTimer bk_scheduledTimerWithTimeInterval:1 block:^(NSTimer *timer) {
[self updateSoundProgress];
} repeats:YES];
}
Let’s hook up our actions in the controller.
Slider
- (void)updateSoundProgress {
self.currentTimeLabel.text = [self formatTimeSeconds:(int) self.sound.currentTime];
self.progressSlider.value = (float) self.sound.currentTime;
}
#pragma mark - Storyboard Outlets
- (IBAction)playProgressChange:(id)sender {
self.sound.currentTime = self.progressSlider.value;
[self updateSoundProgress];
}
Play/Pause, Skip and Next
- (IBAction)playClick:(UIButton *)sender {
self.soundStoppedByUser = NO;
sender.selected = !sender.selected;
if (sender.selected) {
// Play
[self.sound play];
} else {
// Pause
self.soundStoppedByUser = YES;
[self.sound stop];
}
}
- (IBAction)skipNextClick:(id)sender {
if (self.index < self.content.count - 1) {
++self.index;
self.soundStoppedByUser = YES;
[self.sound stop];
[self performSelector:@selector(start) withObject:nil afterDelay:1];
}
}
- (IBAction)skipPreviousClick:(id)sender {
if (self.index > 0) {
--self.index;
self.soundStoppedByUser = YES;
[self.sound stop];
[self performSelector:@selector(start) withObject:nil afterDelay:1];
}
}
You want to be notified when the music ends? Its easy, just subscribe to the SoundDidFinishPlayingNotification
.
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if (!self.sound) {
[self start];
}
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self];
[self.sound stop];
}
- (void)start {
[self updateViews];
[self beginPlaying];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(soundDidFinishPlaying:) name:@"SoundDidFinishPlayingNotification" object:nil];
}
- (void)soundDidFinishPlaying:(id)sender {
if (!self.soundStoppedByUser) {
// TODO Sound stopped playing. Do something?
}
}
That’s all you need to get a simple music player in your app. You could do several things with it, of course. Have the app sync external content and play within your app, or release your app with packaged content (e.g. An app for your album, travel guides etc.).