iOS播放音樂读处、后臺播放、控制臺控制相關(guān)的一些TIPS妙啃,基于StreamingKit

首先給大家放一個(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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末歹嘹,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子孔庭,更是在濱河造成了極大的恐慌尺上,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件圆到,死亡現(xiàn)場離奇詭異怎抛,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)芽淡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進(jìn)店門马绝,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人挣菲,你說我怎么就攤上這事富稻。” “怎么了白胀?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵椭赋,是天一觀的道長。 經(jīng)常有香客問我或杠,道長纹份,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮蔓涧,結(jié)果婚禮上件已,老公的妹妹穿的比我還像新娘。我一直安慰自己元暴,他們只是感情好篷扩,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著茉盏,像睡著了一般鉴未。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上鸠姨,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天铜秆,我揣著相機(jī)與錄音,去河邊找鬼讶迁。 笑死连茧,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的巍糯。 我是一名探鬼主播啸驯,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼祟峦!你這毒婦竟也來了罚斗?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤宅楞,失蹤者是張志新(化名)和其女友劉穎针姿,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體厌衙,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡距淫,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了迅箩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片溉愁。...
    茶點(diǎn)故事閱讀 38,577評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡处铛,死狀恐怖饲趋,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情撤蟆,我是刑警寧澤奕塑,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站家肯,受9級特大地震影響龄砰,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一换棚、第九天 我趴在偏房一處隱蔽的房頂上張望式镐。 院中可真熱鬧,春花似錦固蚤、人聲如沸娘汞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽你弦。三九已至,卻和暖如春燎孟,著一層夾襖步出監(jiān)牢的瞬間禽作,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工揩页, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留旷偿,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓碍沐,卻偏偏與公主長得像狸捅,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子累提,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評論 2 348

推薦閱讀更多精彩內(nèi)容

  • iOS 4開始引入的multitask尘喝,我們可以實(shí)現(xiàn)像ipod程序那樣在后臺播放音頻了。如果音頻操作是用蘋果官方的...
    _烈日閱讀 7,809評論 0 1
  • @(iOS Study)[音視頻播放] 作者: Liwx 郵箱: 1032282633@qq.com 目錄 02....
    Liwx閱讀 2,166評論 5 15
  • 時(shí)光從來都是一視同仁的斋陪,不會因?yàn)槟忝利愋嗤省⑵痢⒂胁湃A就讓你在某個(gè)時(shí)期停留很久无虚,高中三年很短缔赠,高三顯得更短,做...
    6d51948fdd8b閱讀 188評論 0 1
  • 這不是一則寓言故事友题,而是關(guān)于階層固化地位懸殊總有人自恃高人一等的故事嗤堰。 天橋上,一對父子在行乞度宦,破破爛爛的衣服踢匣,頭...
    希文啊閱讀 581評論 0 1
  • 已婚男人通常如帶刺的玫瑰,讓女人進(jìn)退兩難戈抄。繼續(xù)相處吧离唬,這沒名沒份的跟著何時(shí)是個(gè)頭?離他遠(yuǎn)去吧划鸽,但是他又擁有年輕男子...
    妖嬈凡塵閱讀 193評論 0 1