//  ViewController.h
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h> @class AVAudioPlayer; @interface PlayViewController : UIViewController<AVAudioPlayerDelegate> @property(nonatomic, strong) AVAudioPlayer *player; + (PlayViewController *)defaultPlayVC; //将该播放页面定义成单例 @end
//  ViewController.m
#import "PlayViewController.h" @interface PlayViewController () @property (retain, nonatomic) IBOutlet UIButton *suspendBtn; //暂停按钮
@property (retain, nonatomic) IBOutlet UIButton *formerBtn; //上一首按钮
@property (retain, nonatomic) IBOutlet UIButton *nextBtn; //下一首按钮
@property (retain, nonatomic) IBOutlet UISlider *slider; //滑块
@property (retain, nonatomic) NSArray *musicUrlArray; //音乐网址数组
@property (retain, nonatomic) NSArray *musicAllTimeArray; //音乐时间数组
@property (retain, nonatomic) NSTimer *timer; //计时器
@property (assign, nonatomic) int currentIndex; //当前音频下标 @end @implementation PlayViewController
#pragma mark 单例初始化方法
+ (PlayViewController *)defaultPlayVC {
static PlayViewController *playVC = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
playVC = [[PlayViewController alloc] init];
});
return playVC;
} - (void)viewDidLoad {
[super viewDidLoad];
self.currentIndex = 0;
self.musicUrlArray = [NSArray arrayWithObjects:@"http://fdfs.xmcdn.com/group10/M08/D4/2E/wKgDaVZ9EYaQ-j48AFIOaAXL-wM019.mp3",
@"http://fdfs.xmcdn.com/group13/M09/D4/17/wKgDXVZ6fR2wR1E8AFuO_VClRZA066.mp3",
@"http://fdfs.xmcdn.com/group16/M0A/D5/16/wKgDbFZ89SqyFGWGAHoEKd7yPsw709.mp3",
@"http://fdfs.xmcdn.com/group8/M01/D4/34/wKgDYFZ6y1nR6QpZAEDVy7rUTTc247.mp3",
@"http://fdfs.xmcdn.com/group9/M00/D4/EF/wKgDZlZ7aLGCQEEDAHMsQsurq_Y170.mp3",
@"http://fdfs.xmcdn.com/group12/M07/D4/C4/wKgDW1Z70rWxoDA7ABAp1lwS5nI990.mp3", nil];
self.musicAllTimeArray = [NSArray arrayWithObjects:@(1344.36), @(1500.04), @(1999.06), @(1062.22), @(1886.96), @(264.76), nil]; //滑块
self.slider.minimumValue = 0;
[self.slider addTarget:self action:@selector(changValue:) forControlEvents:UIControlEventValueChanged]; //添加滑动事件
[self.slider setThumbImage:[UIImage imageNamed:@"playProcessDot_n"]forState:UIControlStateNormal]; //播放音频之前先要设置AVAudioSession模式 是它可以后台播放
//并且要在plist文件中 添加required background modes这个key项,并选择"App plays audio or streams audio/video using AirPlay"这个value项。
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategoryPlayback error:nil];
[session setActive:YES error:nil]; [self playerCurrentMusic];
} -(void)playerCurrentMusic { //创建串行队列 (放入线程中,免得页面假死)
dispatch_queue_t serialQueue = dispatch_queue_create("com.audio.www", DISPATCH_QUEUE_SERIAL);
dispatch_async(serialQueue, ^{ NSString *url = self.musicUrlArray[self.currentIndex];
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
self.player = [[AVAudioPlayer alloc] initWithData:data error:nil];
self.player.delegate = self;
[self.player prepareToPlay];
[self.player play]; //滑块
CGFloat allTime = [self.musicAllTimeArray[self.currentIndex] floatValue];
self.slider.maximumValue = allTime; //计时器只能在主线程中
dispatch_async(dispatch_get_main_queue(), ^{
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(reloadAction) userInfo:nil repeats:YES];
});
});
} #pragma mark -- 每1秒 给进度条赋一次值
-(void)reloadAction {
if ([self.player isPlaying]) {
self.slider.value = self.player.currentTime;
}
} #pragma mark 点击暂停
- (IBAction)suspendAction:(UIButton *)sender {
sender.selected = !sender.selected;
if (sender.selected) {
[self.player pause]; //暂停
[sender setTitle:@"播放" forState:UIControlStateSelected];
} else {
[self.player play]; //播放
[sender setTitle:@"暂停" forState:UIControlStateNormal];
}
} #pragma mark 点击上一首
- (IBAction)formerAction:(UIButton *)sender {
[self myPlayFormer]; //播放上一首
} #pragma mark 点击下一首
- (IBAction)nextAction:(UIButton *)sender {
[self myPlayNext]; //播放下一首
} #pragma mark 上一首
-(void)myPlayFormer {
if (self.currentIndex > 0) {
[self.player pause];
self.currentIndex--;
[self playerCurrentMusic];
}
}
#pragma mark 下一首
-(void)myPlayNext {
if (self.currentIndex < self.musicUrlArray.count - 1) {
[self.player pause];
self.currentIndex++;
[self playerCurrentMusic];
}
} /***************** 控制台 *****************/
#pragma mark -- 声明App接收远程控制事件
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
} #pragma mark -- App结束声明接收远程控制事件
- (void) viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[[UIApplication sharedApplication] endReceivingRemoteControlEvents];
[self resignFirstResponder];
} #pragma mark -- 接受控制台的控制事件
- (void)remoteControlReceivedWithEvent: (UIEvent *) receivedEvent {
if (receivedEvent.type == UIEventTypeRemoteControl) {
//判断点击按钮的类型
switch (receivedEvent.subtype) { case UIEventSubtypeRemoteControlPlay:
[self.player play]; //播放
break;
case UIEventSubtypeRemoteControlPause:
[self.player pause]; //暂停
break;
case UIEventSubtypeRemoteControlPreviousTrack:
[self myPlayFormer]; //播放上一首
break;
case UIEventSubtypeRemoteControlNextTrack:
[self myPlayNext]; //播放下一首
break;
default:
break;
}
}
} #pragma mark 实现后台播放完一首后, 继续播放下一首
- (BOOL)canBecomeFirstResponder {
return YES;
} /***************** AVAudioPlayer 代理 *****************/
#pragma mark -- 后台播放被打断, 继续恢复播放 (比如打电话...)
- (void)audioPlayerEndInterruption:(AVAudioPlayer *)player withOptions:(NSUInteger)flags {
[self.player play];
}
#pragma mark -- 播放完当前声音后,播放下一首
-(void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {
if (self.currentIndex < self.musicUrlArray.count - 1) {
self.currentIndex++;
[self playerCurrentMusic];
}
} #pragma mark -- 滑块滑动改变播放进度(代理方法)
-(void)changValue:(UISlider *)slider {
//拖动滑块时, 停止计时器
[self.timer invalidate];
self.player.currentTime = slider.value;
//开始计时器
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(reloadAction) userInfo:nil repeats:YES];
}

想要实现后台播放(即程序进入后台,音乐继续播放)需要修改plist文件:

1.添加required background modes这个key项,并选择"App plays audio or streams audio/video using AirPlay"这个value项。
2.XCode7.1以上获取网络数据,需要修改plist文件
在Info.plist中添加App Transport Security Settings类型Dictionary。
在App Transport Security Settings下添加Allow Arbitrary Loads类型Boolean,值设为YES

需要在后台实现播放页的各种上一首,下一首...各种功能, 还需要在Appdelegate.m的background方法里:

- (void)applicationDidEnterBackground:(UIApplication *)application {

    //程序进入后台后, 为了让音乐继续播放, 在此方法里创建该代理播放页, 并指定它播放器的代理
PlayViewController *player = [PlayViewController defaultPlayVC];
player.player.delegate = player;
}

当前工程Demo地址: http://download.csdn.net/detail/margaret_mo/9412069

最新文章

  1. 腾讯AlloyTeam移动Web裁剪组件AlloyCrop正式开源
  2. [转]完美洗牌(Perfect Shuffle)问题
  3. Ubuntu 16.04安装QQ国际版图文详细教程
  4. Window 对象详解 转自 http://blog.csdn.net/jcx5083761/article/details/41243697
  5. 在UWP应用中加入Cortana语音指令集
  6. Design1:数据层次结构建模之一
  7. svn更新报错:svn unable to connect to a repository at url
  8. 怎么写jq插件?
  9. The name &#39;Scripts&#39; does not exist in the current context error in MVC
  10. BZOJ 3143 HNOI2013 游走 高斯消元 期望
  11. CentOs install oracle instant client
  12. Css实现垂直水平居中的六种方法
  13. 信息熵(Entropy)究竟是用来衡量什么的?
  14. JQuery实现两侧浮动广告
  15. Flask 学习 十 博客文章
  16. Flask 学习 八 用户角色
  17. Jrebel最新激活破解方式以及一些必要的配置支持
  18. java如何快速创建List
  19. mySql版本的相关问题:com.mysql.cj.jdbc.Driver和com.mysql.jdbc.Driver
  20. SqlDateTime overflow / SqlDateTime 溢出

热门文章

  1. Azure操作手册集合
  2. Windows Azure Web Site (17) Azure Web Site 固定公网IP地址
  3. 基于HTML5的3D网络拓扑自动布局
  4. 《ASP.NET SignalR系列》第五课 在MVC中使用SignalR
  5. GPUimage实时滤镜的实现
  6. 枚举 + 进制转换 --- hdu 4937 Lucky Number
  7. dp or 贪心 --- hdu : Road Trip
  8. C# CGI程序
  9. TabHost的使用
  10. 【Java每日一题】20161128