首先給大家放一個(gè)StreamingKit的鏈接
簡單的播放使用例子,可以看開源作者的演示demo俊戳。
由于整個(gè)播放器涉及到UI啊數(shù)據(jù)啊比較多揖赴,所以就不全摳下來當(dāng)demo了,就在這里列一點(diǎn)TIPS抑胎,希望能幫助到大家燥滑。
歌曲播放形式我是這么寫的:
.h里:
/**
歌曲播放形式
*/
typedef enum : NSUInteger {
MBAudioPlayTypeCircle, //循環(huán)播放
MBAudioPlayTypeRandom, //隨機(jī)播放
MBAudioPlayTypeOneMusic,//單曲循環(huán)
MBAudioPlayTypeNoNext, //播完就不播了
} MBAudioPlayType;
.m里:
/**
* 下一首
*/
- (void)playNextMusic
{
switch (self.playType) {
case MBAudioPlayTypeCircle:
{
//循環(huán)播放
_nowMusicLocal++;
if (_nowMusicLocal >= [self allLocal]) {
_nowMusicLocal = 0;
}
[self playMusic];
}
break;
case MBAudioPlayTypeRandom:
{
//隨機(jī)播放
[self randomWithTimes:5];
if (_nowMusicLocal >= [self allLocal]) {
_nowMusicLocal = 0;
}
[self playMusic];
}
break;
case MBAudioPlayTypeOneMusic:
{
//單曲循環(huán)
[self playMusicWithInfo];
}
break;
case MBAudioPlayTypeNoNext:
{
//播完就不播了
}
break;
default:
break;
}
}
#pragma mark - 隨機(jī)播放隨機(jī)數(shù)
/**
* 隨機(jī)遞歸
*
* @param num 遞歸次數(shù)
*/
-(void)randomWithTimes:(NSInteger)num
{
NSInteger randomMusic = arc4random() % [self allLocal];
DLog(@"隨機(jī)值為:%ld",(long)randomMusic);
if (_nowMusicLocal == randomMusic && [self allLocal] != 1) {
//防止遞歸死循環(huán)
if (num != 0) {
num--;
[self randomWithTimes:num];
return;
}else
{
randomMusic++;
//遞歸多次還一樣,就強(qiáng)行設(shè)一個(gè)了(低概率事件)
_nowMusicLocal = randomMusic;
}
}
else
{
//正常情況
_nowMusicLocal = randomMusic;
}
}
這個(gè)隨機(jī)算法寫的其實(shí)挺搓的阿逃,不過勉強(qiáng)能用吧铭拧。。恃锉。
獲取后臺播放權(quán)限
在target-capabilities-background modes 開啟 audio and airplay
在AppDelegate中
#import <AVFoundation/AVFoundation.h>
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
xxxxx;
NSError* error;
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&error];
}
漏掉最重要的了搀菩,在程序掛起的時(shí)候,要手動加權(quán)限的破托,
- (void)applicationWillResignActive:(UIApplication *)application
{
DLog(@"\n\n倔強(qiáng)的打出一行字告訴你我要掛起了肪跋。。\n\n");
//MBAudioPlayer是我為播放器寫的單例土砂,這段就是當(dāng)音樂還在播放狀態(tài)的時(shí)候州既,給后臺權(quán)限谜洽,不在播放狀態(tài)的時(shí)候,收回后臺權(quán)限
if ([MBAudioPlayer shareInstance].audioPlayer.state == STKAudioPlayerStatePlaying||[MBAudioPlayer shareInstance].audioPlayer.state == STKAudioPlayerStateBuffering||[MBAudioPlayer shareInstance].audioPlayer.state == STKAudioPlayerStatePaused ||[MBAudioPlayer shareInstance].audioPlayer.state == STKAudioPlayerStateStopped) {
//有音樂播放時(shí)吴叶,才給后臺權(quán)限阐虚,不做流氓應(yīng)用。
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
//開啟定時(shí)器
[[MBAudioPlayer shareInstance] decideTimerWithType:MBAudioTimerStartBackground andBeginState:YES];
[[MBAudioPlayer shareInstance] configNowPlayingInfoCenter];
}
else
{
[[UIApplication sharedApplication] endReceivingRemoteControlEvents];
[self resignFirstResponder];
//檢測是都關(guān)閉定時(shí)器
[[MBAudioPlayer shareInstance] decideTimerWithType:MBAudioTimerStartBackground andBeginState:NO];
}
}
鎖屏?xí)r蚌卤,更新控制臺实束、鎖屏信息(定時(shí)器調(diào)用)
#pragma mark - 鎖屏控制
/**
* 設(shè)置鎖屏信息
*/
-(void)configNowPlayingInfoCenter
{
if (self.nowPlayingMusicInfo == nil) {
return;
}
@autoreleasepool {
NSDictionary *info = self.nowPlayingMusicInfo;
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
//歌曲名稱
[dict setObject:[info ObjectNullForKey:@"title"] forKey:MPMediaItemPropertyTitle];
//演唱者
[dict setObject:[info ObjectNullForKey:@"author"] forKey:MPMediaItemPropertyArtist];
//專輯名
//[dict setObject:[info ObjectNullForKey:@"album"] forKey:MPMediaItemPropertyAlbumTitle];
//專輯縮略圖
NSString *imagePath = [info ObjectNullForKey:@"thumb"];
imagePath = [NSString stringWithFormat:@"EGOImageLoader-%lu", (unsigned long)[[imagePath description] hash]];
NSString *imageLocalPath = [NSString stringWithFormat:@"%@/%@", EGOCacheDirectory(),imagePath];
NSData * thumbData = [NSData dataWithContentsOfFile:imageLocalPath];
if (thumbData != nil) {
UIImage *image = [UIImage imageWithData:thumbData];
MPMediaItemArtwork *artwork = [[MPMediaItemArtwork alloc] initWithImage:image];
[dict setObject:artwork forKey:MPMediaItemPropertyArtwork];
}else
{
// FIXME: 無圖的時(shí)候,讀取圖
}
//音樂剩余時(shí)長
[dict setObject:[NSNumber numberWithDouble:self.audioPlayer.duration] forKey:MPMediaItemPropertyPlaybackDuration];
//音樂當(dāng)前播放時(shí)間 在計(jì)時(shí)器中修改
[dict setObject:[NSNumber numberWithDouble:self.audioPlayer.progress] forKey:MPNowPlayingInfoPropertyElapsedPlaybackTime];
//設(shè)置鎖屏狀態(tài)下屏幕顯示播放音樂信息
//DLog(@"顯示播放音樂信息:%@\n%@",dict,[info ObjectNullForKey:@"title"]);
[[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:dict];
}
}
/**
* 響應(yīng)遠(yuǎn)程音樂播放控制消息
*
* @param receivedEvent
*/
- (void)remoteControlReceivedWithEvent:(UIEvent *)receivedEvent {
if (receivedEvent.type == UIEventTypeRemoteControl) {
switch (receivedEvent.subtype) {
case UIEventSubtypeRemoteControlPause:
//點(diǎn)擊了暫停
[self pauseStreamer];
break;
case UIEventSubtypeRemoteControlNextTrack:
//點(diǎn)擊了下一首
[self playNextMusic];
break;
case UIEventSubtypeRemoteControlPreviousTrack:
//點(diǎn)擊了上一首
[self playPreMusic];
//此時(shí)需要更改歌曲信息
break;
case UIEventSubtypeRemoteControlPlay:
//點(diǎn)擊了播放
[self pauseStreamer];
break;
default:
break;
}
}
}
最后造寝,那些在鎖屏中帶歌詞的產(chǎn)品么磕洪,據(jù)說是不停的的把歌詞和專輯圖片結(jié)合在一起,然后根據(jù)歌詞時(shí)間刷新圖片诫龙。析显。。如果有這個(gè)產(chǎn)品需求签赃,可以按這個(gè)思路來做谷异。。
簡書已經(jīng)棄用锦聊,歡迎移步我的小專欄:
https://xiaozhuanlan.com/dahuihuiiOS