AVAudioPlayer本地音乐播放、后台播放、歌词同步,都告诉你
来源:互联网 发布:维氏瑞士军刀淘宝 编辑:程序博客网 时间:2024/05/01 14:40
后台播放配置
1、打开项目的Capabilities中的Background Models 勾选第一个选项
2、设置音乐后台播放的会话类型,开启远程事件(锁屏时使用)
//设置音乐后台播放的会话类型 AVAudioSession *session = [AVAudioSession sharedInstance]; NSError *error = nil; [session setCategory:AVAudioSessionCategoryPlayback error:&error]; if (error) { NSLog(@"%s %@", __func__, error); } [session setActive:YES error:nil]; //开启远程事件(锁屏时使用) [application beginReceivingRemoteControlEvents];
3、实现远程事件回调方法
#pragma mark 接收远程事件-(void)remoteControlReceivedWithEvent:(UIEvent *)event{ //判断是否为远程事件 if (event.type == UIEventTypeRemoteControl) { //调用block self.myRemoteEventBlock(event); }}
4、处理回调block
//锁屏后 事件 myAppDel.myRemoteEventBlock = ^(UIEvent *event) { switch (event.subtype) { case UIEventSubtypeRemoteControlPlay: [[MusicPlayTool sharedMusicPlayTool] play]; break; case UIEventSubtypeRemoteControlPause: [[MusicPlayTool sharedMusicPlayTool] pause]; break; case UIEventSubtypeRemoteControlPreviousTrack: [[MusicPlayTool sharedMusicPlayTool] prepareForPlayWithMusic:[[MusicManager sharedMusicManager] upMusicInfo]]; [[MusicPlayTool sharedMusicPlayTool] play]; break; case UIEventSubtypeRemoteControlNextTrack: [[MusicPlayTool sharedMusicPlayTool] prepareForPlayWithMusic:[[MusicManager sharedMusicManager] nextMusicInfo]]; [[MusicPlayTool sharedMusicPlayTool] play]; break; default: break; } };
经过上面四步,app能后台播放音乐,并且能捕捉上一首歌、下一首歌、暂停和播放事件。但是锁屏的时候并没有相关的音乐的信息。运行效果如下图。
设置锁屏信息
NSMutableDictionary *info = [NSMutableDictionary dictionary]; //设置专辑名称 info[MPMediaItemPropertyAlbumTitle] = @"网络热曲"; //设置歌曲名 info[MPMediaItemPropertyTitle] = music.musicName; //设置歌手 info[MPMediaItemPropertyArtist] = music.songer; //设置专辑图片 MPMediaItemArtwork *artwork = [[MPMediaItemArtwork alloc] initWithImage:[UIImage imageNamed:@"song_400"]]; info[MPMediaItemPropertyArtwork] = artwork; //设置歌曲时间 info[MPMediaItemPropertyPlaybackDuration] = @(self.player.duration); [MPNowPlayingInfoCenter defaultCenter].nowPlayingInfo = info;
运行效果
歌词解析、歌词同步
目前的歌词都是lrc文件,格式如些
[ti:为情所伤][ar:庄心妍][al:][00:00.00]为情所伤[00:02.00]演唱:庄心妍[00:04.00]作词:镜喜 作曲:祁隆[00:06.00]编曲:颜小健[00:08.00]混音:王路遥[00:10.00]音乐总监:祁隆[00:12.00][00:20.02]你说不会在爱情里犯错[00:23.83]也说过会永远的爱我[00:27.60]才发现只剩下虚伪的承诺[00:31.79]用泪水把回忆包裹[00:35.41]我也曾经想把爱去闪躲[00:39.22]可摆脱不了那份寂寞[00:42.94]结果都是让我一错再错[00:47.06]被伤过的心再次漂泊[00:50.48]为什么爱留下难忍的伤[00:54.19]心里的酸楚要去遗忘[00:58.25]看见的是一道封闭的墙[01:02.05]什么时候能打开一扇窗[01:05.73]为什么爱留下难忍的伤[01:09.53]泪水无情拍打着海浪[01:13.38]谁能给我一双温暖的浆[01:17.57]不让我 再为情所伤[01:24.04][01:39.91]你说不会在爱情里犯错[01:43.90]也说过会永远的爱我[01:47.64]才发现只剩下虚伪的承诺[01:51.83]用泪水把回忆包裹[01:55.26]我也曾经想把爱去闪躲[01:59.23]可摆脱不了那份寂寞[02:02.98]结果都是让我一错再错[02:07.08]被伤过的心再次漂泊[02:10.50]为什么爱留下难忍的伤[02:14.17]心里的酸楚要去遗忘[02:18.11]看见的是一道封闭的墙[02:21.96]什么时候能打开一扇窗[02:25.69]为什么爱留下难忍的伤[02:29.43]泪水无情拍打着海浪[02:33.38]谁能给我一双温暖的浆[02:37.32]不让我 再为情所伤[02:40.89]为什么爱留下难忍的伤[02:44.68]心里的酸楚要去遗忘[02:48.65]看见的是一道封闭的墙[02:52.48]什么时候能打开一扇窗[02:56.19]为什么爱留下难忍的伤[03:00.01]泪水无情拍打着海浪[03:03.94]谁能给我一双温暖的浆[03:07.97]不让我 再为情所伤[03:14.57]
为了简单,不考虑上面的[ti:为情所伤]、[ar:庄心妍]、[al:]这个快内容。其余下面的部分都是采用时间+当前时间开始的歌词。那么解析思路就是把一句的时间(转换成秒)跟当前的歌词分离出来然后用字典保存,由于字典是无序的,所以再用一个数字一次保存当前的时间。代码如下:
//解析歌词 MusicInfo *currentModel = [MusicManager sharedMusicManager].currentMusic; [self.lrcTimeArr removeAllObjects]; [self.lrcDic removeAllObjects]; if (currentModel.lrc.length>0) { NSString *str = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:currentModel.lrc ofType:nil] encoding:NSUTF8StringEncoding error:nil]; NSArray *allRowArr = [str componentsSeparatedByString:@"\n"]; for (int i = 0; i < allRowArr.count; i++) { NSString *linStr = [allRowArr objectAtIndex:i]; NSArray *lineArray = [linStr componentsSeparatedByString:@"]"]; if ([lineArray[0] length] > 4) { NSString *str1 = [linStr substringWithRange:NSMakeRange(3, 1)]; NSString *str2 = [linStr substringWithRange:NSMakeRange(6, 1)]; NSString *str3 = [linStr substringWithRange:NSMakeRange(1, 1)]; if (([str1 isEqualToString:@":"] && [str2 isEqualToString:@"." ]) || ([str1 isEqualToString:@":"]&&[str2 isEqualToString:@"]"]&&[str3 isEqualToString:@"0"])) { NSString *lrcStr = [lineArray objectAtIndex:1]; NSString *timeStr = [[lineArray objectAtIndex:0] substringWithRange:NSMakeRange(1, 5)];//分割区间求歌词时间 NSArray *array = [timeStr componentsSeparatedByString:@":"];//把时间转换成秒 NSUInteger currentTime = [array[0] intValue] * 60 + [array[1] intValue]; NSString *str = [NSString stringWithFormat:@"%ld",currentTime]; //把时间 和 歌词 加入词典 [self.lrcDic setObject:lrcStr forKey:str]; [self.lrcTimeArr addObject:str];//timeArray的count就是行数 } } } }
当音乐播放时,不断刷新播放进度条的时候,根据当前的currentTime与保存时间的数字里面的时间进行对比选出当前正在播放的时间段,然后通过字典取出当前的歌词,刷新tableView,代码如下:
- (void)upDateUI{ MusicPlayTool *playTool = [MusicPlayTool sharedMusicPlayTool]; self.currentTime.text = [NSString stringWithFormat:@"%02d:%02d",(int)playTool.player.currentTime/60,(int)playTool.player.currentTime%60]; self.progressSlider.value = playTool.player.currentTime; for (int i = 0; i < self.lrcTimeArr.count; i++) { NSString *timeStr = self.lrcTimeArr[i]; if ([timeStr integerValue] == (NSInteger)playTool.player.currentTime) { _currentIndex = i; [self resetLockInfo]; [_lrcTableView reloadData]; [_lrcTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:_currentIndex inSection:0] atScrollPosition:UITableViewScrollPositionMiddle animated:YES]; return; } }}
实际运行效果如下图:
锁屏歌词同步
在设置锁屏信息的时候有这么一句代码:
//设置专辑图片 MPMediaItemArtwork *artwork = [[MPMediaItemArtwork alloc] initWithImage:[UIImage imageNamed:@"song_400"]]; info[MPMediaItemPropertyArtwork] = artwork;
图片“song_400”就是锁屏的是锁屏时中间显示的大图,要显示歌词就要将歌词绘制到图片上面,然后合成生成新的图片显示,代码如下:
//设置专辑图片 //UIImage *image = [UIImage imageNamed:music.icon]; UIImage *image = [self createShareImage:[self.lrcDic objectForKey:self.lrcTimeArr[_currentIndex]] name:@"song_400" number:nil grade:nil];- ( UIImage *)createShareImage:( NSString *)str name:( NSString *)name number:( NSString *)number grade:( NSString *)grade{ UIImage *image = [UIImage imageNamed:name]; CGSize size= CGSizeMake (image.size.width, image.size.height); // 画布大小 UIGraphicsBeginImageContextWithOptions(size, NO, 0.0); [image drawAtPoint:CGPointMake(0, 0)]; // 获得一个位图图形上下文 CGContextRef context= UIGraphicsGetCurrentContext (); CGContextDrawPath(context, kCGPathStroke ); CGSize needSize = CGSizeMake(1000,20); NSDictionary *attribute = @{NSFontAttributeName:[UIFont systemFontOfSize:16], NSForegroundColorAttributeName:[UIColor grayColor]}; CGSize labelsize = [str boundingRectWithSize:needSize options: NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:attribute context:nil].size; CGFloat width = MIN(labelsize.width, image.size.width); [str drawInRect:CGRectMake((image.size.width-width)/2, image.size.height - 40, width, 20) withAttributes:attribute]; // 返回绘制的新图形 UIImage *newImage= UIGraphicsGetImageFromCurrentImageContext (); UIGraphicsEndImageContext (); return newImage;}
然后在刷新进度条的时候不停的合成生成新的图片进行显示。
最终运行效果如下:
完整代码github连接(只有2首歌配置了歌词)
0 0
- AVAudioPlayer本地音乐播放、后台播放、歌词同步,都告诉你
- AVAudioPlayer实现音乐播放+歌词与播放进度同步
- AVAudioPlayer本地音乐播放
- AVAudioPlayer 播放本地音乐
- 本地音乐播放AVAudioPlayer
- AVAudioPlayer播放本地音乐
- 本地MediaPlayer音乐播放器与歌词同步的实现
- AVAudioPlayer播放本地音乐AVPlayer播放网络音乐
- 使用AVAudioPlayer播放音乐
- 音乐播放器实现歌词同步
- android 音乐播放器-------歌词同步 lrc
- Android 音乐播放器 实现歌词同步
- 音乐播放器实现歌词同步
- 音频播放AVAudioPlayer后台播放
- iOS_33_音乐播放(后台播放+锁屏歌词)
- iOS_33_音乐播放(后台播放+锁屏歌词)
- ios AVAudioPlayer 后台播放
- AVAudioPlayer后台播放
- max-points-on-a-line
- Poj487-3279
- HTML5游戏开发/微信游戏开发——Cocos2dx-js开发环境搭建(win32平台)
- 关于指针的一点思考
- 获取手机软件缓存的方法(反射)getPackageSizeInfo
- AVAudioPlayer本地音乐播放、后台播放、歌词同步,都告诉你
- myeclipse配置
- UIWebView 前进 后退 刷新 取消
- c语言中的strlen函数
- java.util.Collections.synchronizedSet()方法实例
- Android使用Rxjava异步递归读取内存卡中所有的视频文件
- 详解C/C++预处理器
- JAVA_FINAL关键字
- 监控系统思考