1. 程式人生 > 其它 >【轉】OC-音樂播放器-鎖屏處理

【轉】OC-音樂播放器-鎖屏處理

QQ音樂播放的過程中,鎖屏狀態下的效果如下:

也就是說,QQ音樂播放過程中,新增鎖屏遠端事件的監聽。

本文只記錄本人知道的小知識點,不提供完整的程式碼。

實現的原理:

(1)獲取鎖屏歌曲資訊中心:MPNowPlayingInfoCenter

(2)設定鎖屏下要顯示的歌曲的資訊

(3)啟動遠端事件的監聽

1.MPNowPlayingInfoCenter簡要說明

(1)官方文件對MPNowPlayingInfoCenter的解說如下:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 // -----------------------------------------------------------------------------
// MPNowPlayingInfoCenter provides an interface for setting the current now // playing information for the application. This information will be displayed // wherever now playing information typically appears, such as the lock screen // and app switcher. The now playing info dictionary contains a group of // metadata properties for a now playing item. The list of property constants
// is available in <MediaPlayer/MPMediaItem.h>. The properties which are // currently supported include: // // MPMediaItemPropertyAlbumTitle // MPMediaItemPropertyAlbumTrackCount // MPMediaItemPropertyAlbumTrackNumber // MPMediaItemPropertyArtist // MPMediaItemPropertyArtwork // MPMediaItemPropertyComposer // MPMediaItemPropertyDiscCount
// MPMediaItemPropertyDiscNumber // MPMediaItemPropertyGenre // MPMediaItemPropertyPersistentID // MPMediaItemPropertyPlaybackDuration // MPMediaItemPropertyTitle // // In addition, metadata properties specific to the current playback session // may also be specified -- see "Additional metadata properties" below.

上面那段話大體的意思如下:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 MPNowPlayingInfoCenter(播放資訊中心)為應用程式提供設定當前正在播放的資訊的介面;   此資訊將顯示在正在播放資訊型別呼叫的任何位置,例如鎖屏下或者應用程式切換中;   正在播放的資訊字典包含一組正在播放項的元資料屬性,這些屬性常量列表在<MediaPlayer/MPMediaItem.h>有提供;   這些屬性目前提供的包括:    MPMediaItemPropertyAlbumTitle (標題)    MPMediaItemPropertyAlbumTrackCount(專輯歌曲數)    MPMediaItemPropertyAlbumTrackNumber (專輯歌曲編號)    MPMediaItemPropertyArtist (藝術家/歌手)    MPMediaItemPropertyArtwork (封面圖片 MPMediaItemArtwork 型別)    MPMediaItemPropertyComposer (作曲)    MPMediaItemPropertyDiscCount (專輯數)    MPMediaItemPropertyDiscNumber (專輯編號)    MPMediaItemPropertyGenre (型別\流派)    MPMediaItemPropertyPersistentID (唯一識別符號)   MPMediaItemPropertyPlaybackDuration (歌曲時長)    MPMediaItemPropertyTitle (歌曲名稱)<br><br>  此外,音樂播放必須支援後臺播放的功能。

  另外,當前播放資訊中心還提供了一個方法和一個屬性如下:

/// Returns the default now playing info center.
/// The default center holds now playing info about the current application.
+ (MPNowPlayingInfoCenter *)defaultCenter;/// The current now playing info for the center.
/// Setting the info to nil will clear it.
@property (nonatomic, copy, nullable) NSDictionary<NSString *, id> *nowPlayingInfo;

  也就是說,可以用defaultCenter來獲取當前的MPNowPlayingInfoCenter,然後在nowPlayingInfo 以字典的形式設定 鎖屏中的歌曲資訊。

  其中,這個類,還提供了一些額外的元組屬性,如下:

    MP_EXTERN NSString *const MPNowPlayingInfoPropertyElapsedPlaybackTime  當前時間 NSNumber
     MP_EXTERN NSString *const MPNowPlayingInfoPropertyPlaybackRate
     MP_EXTERN NSString *const MPNowPlayingInfoPropertyDefaultPlaybackRate
     MP_EXTERN NSString *const MPNowPlayingInfoPropertyPlaybackQueueIndex
     MP_EXTERN NSString *const MPNowPlayingInfoPropertyPlaybackQueueCount
     MP_EXTERN NSString *const MPNowPlayingInfoPropertyChapterNumber
     MP_EXTERN NSString *const MPNowPlayingInfoPropertyChapterCount
     MP_EXTERN NSString *const MPNowPlayingInfoPropertyAvailableLanguageOptions   MPNowPlayingInfoLanguageOptionGroup
     MP_EXTERN NSString *const MPNowPlayingInfoPropertyCurrentLanguageOptions

  找到了一個對這些屬性解說不錯的文件:

  蹩腳英文翻譯系列:(未標註版本的鍵均為iOS8及以下可用)
NameTypemeaning
MPMediaItemPropertyAlbumTitle NSString 專輯歌曲數
MPMediaItemPropertyAlbumTrackCount NSNumber of NSUInteger 專輯歌曲數
MPMediaItemPropertyAlbumTrackNumber NSNumber of NSUInteger 藝術家/歌手
MPMediaItemPropertyArtist NSString 藝術家/歌手
MPMediaItemPropertyArtwork MPMediaItemArtwork 封面圖片 MPMediaItemArtwork型別
MPMediaItemPropertyComposer NSString 作曲
MPMediaItemPropertyDiscCount NSNumber of NSUInteger 專輯數
MPMediaItemPropertyDiscNumber NSNumber of NSUInteger 專輯編號
MPMediaItemPropertyGenre NSString 型別/流派
MPMediaItemPropertyPersistentID NSNumber of uint64_t 唯一識別符號
MPMediaItemPropertyPlaybackDuration NSNumber of NSTimeInterval 歌曲時長 NSNumber型別
MPMediaItemPropertyTitle NSString 歌曲名稱
MPNowPlayingInfoPropertyElapsedPlaybackTime NSNumber (double) 在播資源的時間流逝,s為單位。流逝時間會從播放時間和播放速率中自動計算,不合適頻繁得更新
MPNowPlayingInfoPropertyPlaybackRate NSNumber (double) 在播資源的速率(保持與APP內播放器的速率一致)
MPNowPlayingInfoPropertyDefaultPlaybackRate NSNumber (double) 在播資源的“預設”播放速率,當你的APP需要播放資源的播放速率預設都是大於1的,那麼就應該使用這屬性
MPNowPlayingInfoPropertyPlaybackQueueIndex NSNumber (NSUInteger) 應用重放佇列中,當前播放項的索引。注意索引值從0開始
MPNowPlayingInfoPropertyPlaybackQueueCount NSNumber (NSUInteger) 應用重放佇列的總資源數目
MPNowPlayingInfoPropertyChapterNumber NSNumber (NSUInteger) 這在播放的部分,索引值從0開始
MPNowPlayingInfoPropertyChapterCount NSNumber (NSUInteger) 在播資源的總章節數目
MPNowPlayingInfoPropertyIsLiveStream(iOS 10.0) NSNumber (BOOL) 表示當前的資源是不是實時流
MPNowPlayingInfoPropertyAvailableLanguageOptions(iOS 9.0) NSArrayRef of MPNowPlayingInfoLanguageOptionGroup 在播資源的一組可用的語言型別。在給定組中一次只能播放一種語言型別的資源
MPNowPlayingInfoPropertyCurrentLanguageOptions(iOS 9.0) NSArray of MPNowPlayingInfoLanguageOption 當前播放專案的語言選項列表
MPNowPlayingInfoCollectionIdentifier(iOS 9.3) NSString 表示當前播放資源所歸屬的那個集合的識別符號,可指作者、專輯、播放列表等。可用於請求重新播放這個集合。
MPNowPlayingInfoPropertyExternalContentIdentifier(iOS 10.0) NSString 一個不暴露的唯一標誌符,標誌當前正在播放的item,貫穿APP重啟。可使用任何格式,僅用於引用這個item和返回到正在播放資源的APP中
MPNowPlayingInfoPropertyExternalUserProfileIdentifier(iOS 10.0) NSString 一個可選型的不暴露的標誌,標誌當前正在播放的資源的配置檔案,貫穿APP重啟。可使用任何格式,僅用於返回到這個配置檔案對應的正在播放視訊的APP
MPNowPlayingInfoPropertyServiceIdentifier(iOS 11.0) NSString 服務商的唯一標誌。如果當前播放的資源屬於一個頻道或者是定於的服務型別,這個ID可以用於區分和協調特定服務商的多種資源型別
MPNowPlayingInfoPropertyPlaybackProgress(iOS 10.0) NSNumber (float) 表示當前播放資源的播放進度,0.0表示未開始,1.0表示完全瀏覽完。區分於ElapsedPlaybackTime,無需更高的精度要求。如:當字幕開始滾動時,這個電影可能被使用者期望開始播放(由字幕驅動播放進度)
MPNowPlayingInfoPropertyMediaType NSNumber (MPNowPlayingInfoMediaType) 指定當前媒體型別,用於確定系統顯示的使用者介面型別
MPNowPlayingInfoPropertyAssetURL(iOS 10.3) NSURL 指向當前正播放的視訊或音訊資源的URL。可將視訊縮圖或者音訊的波普圖使用於系統的UI上
(2)參考到連結:https://www.jianshu.com/p/21396afffe62

2.鎖屏下要顯示歌曲資訊的設定

  從上文中,已經可以知道,用

MPNowPlayingInfoCenter *center = [MPNowPlayingInfoCenter defaultCenter];

來獲取鎖屏資訊控制中心,然後把鎖屏情況下要顯示的圖片、歌曲名字、歌手、歌詞、時間等資訊以字典的形式賦值給center的nowPlayInfo屬性。

示例程式碼如下:

  MPNowPlayingInfoCenter *center = [MPNowPlayingInfoCenter defaultCenter];
    NSMutableDictionary *infoDic = [NSMutableDictionary dictionary];
    [infoDic setObject:@"泡沫" forKey:MPMediaItemPropertyAlbumTitle];
    [infoDic setObject:@"歌手" forKey:MPMediaItemPropertyArtist];
    [infoDic setObject:[[MPMediaItemArtwork alloc] initWithImage:[UIImage imageNamed:@"61149b0491243c749fc871e67550a7f6"]] forKey:MPMediaItemPropertyArtwork];
    [infoDic setObject:@"200" forKey:MPMediaItemPropertyPlaybackDuration];
    [infoDic setObject:@"歌詞" forKey:MPMediaItemPropertyTitle];
    center.nowPlayingInfo = infoDic;

 

3.鎖屏遠端事件的監聽的簡要說明:

(1)ios71.版本

  可以用的是[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];

  然後監聽remoteControlReceivedWithEvent:這個方法,

  event的類中有UIEventSubtype的subtype。

  subtype的型別如下:

typedef NS_ENUM(NSInteger, UIEventSubtype) {
    // available in iPhone OS 3.0
    UIEventSubtypeNone                              = 0,
    
    // for UIEventTypeMotion, available in iPhone OS 3.0
    UIEventSubtypeMotionShake                       = 1,
    
    // for UIEventTypeRemoteControl, available in iOS 4.0
    UIEventSubtypeRemoteControlPlay                 = 100,   //播放
    UIEventSubtypeRemoteControlPause                = 101,   //暫停
    UIEventSubtypeRemoteControlStop                 = 102,   //停止
    UIEventSubtypeRemoteControlTogglePlayPause      = 103,   //耳機上的播放暫停命令
    UIEventSubtypeRemoteControlNextTrack            = 104,   //下一首
    UIEventSubtypeRemoteControlPreviousTrack        = 105,   //上一首
    UIEventSubtypeRemoteControlBeginSeekingBackward = 106,   //開始後退
    UIEventSubtypeRemoteControlEndSeekingBackward   = 107,   //後退結束
    UIEventSubtypeRemoteControlBeginSeekingForward  = 108,   //開始快進
    UIEventSubtypeRemoteControlEndSeekingForward    = 109,   //快進結束
};

- (void)remoteControlReceivedWithEvent:(UIEvent *)event {

NSLog(@"---event.type = %ld", (long)event.subtype);

 //在這裡面監聽操作的型別

}

(2)iOS7.1以後

  可以使用MPRemoteCommandCenter這個類的方法,這個類提供了一個類方法:sharedCommandCenter;

  提供一個不錯可參考的連結:https://www.jianshu.com/p/b9cc97db16b8

  MPRemoteCommandCenter是獲取到這個單例物件後,使用共享的這個MPRemoteCommand物件,用於響應各種遠端控制事件配置自己的需求。
如:像網易雲音樂一樣,在鎖屏以及多媒體系統UI介面配置滑動播放進度(seekTime),下一曲,上一曲,喜歡,不喜歡等配置;    

  MPRemoteCommandCenter提供的配置資訊如下:

// Playback Commands
@property (nonatomic, readonly) MPRemoteCommand *pauseCommand;   //暫停
@property (nonatomic, readonly) MPRemoteCommand *playCommand;    //播放
@property (nonatomic, readonly) MPRemoteCommand *stopCommand;    //停止
@property (nonatomic, readonly) MPRemoteCommand *togglePlayPauseCommand;  //耳機線控制暫停和播放
@property (nonatomic, readonly) MPRemoteCommand *enableLanguageOptionCommand MP_API(ios(9.0), macos(10.12.2));  //不知
@property (nonatomic, readonly) MPRemoteCommand *disableLanguageOptionCommand MP_API(ios(9.0), macos(10.12.2)); //不知
@property (nonatomic, readonly) MPChangePlaybackRateCommand *changePlaybackRateCommand;     //不知
@property (nonatomic, readonly) MPChangeRepeatModeCommand *changeRepeatModeCommand;         //不知
@property (nonatomic, readonly) MPChangeShuffleModeCommand *changeShuffleModeCommand;       不知

// Previous/Next Track Commands
@property (nonatomic, readonly) MPRemoteCommand *nextTrackCommand;    //下一首
@property (nonatomic, readonly) MPRemoteCommand *previousTrackCommand;  //上一首

// Skip Interval Commands
@property (nonatomic, readonly) MPSkipIntervalCommand *skipForwardCommand;  //快進幾秒(如果與下一首同時設定,優先顯示快進)
@property (nonatomic, readonly) MPSkipIntervalCommand *skipBackwardCommand; //快退幾秒(如果與上一首同時設定,優先顯示快退)

// Seek Commands
@property (nonatomic, readonly) MPRemoteCommand *seekForwardCommand;   //不知
@property (nonatomic, readonly) MPRemoteCommand *seekBackwardCommand;  //不知
@property (nonatomic, readonly) MPChangePlaybackPositionCommand *changePlaybackPositionCommand MP_API(ios(9.1), macos(10.12.2));

// Rating Command
@property (nonatomic, readonly) MPRatingCommand *ratingCommand;   //設定倍速,不知道在哪裡顯示

// Feedback Commands
// These are generalized to three distinct actions. Your application can provide
// additional context about these actions with the localizedTitle property in
// MPFeedbackCommand.
@property (nonatomic, readonly) MPFeedbackCommand *likeCommand;  //設定喜歡
@property (nonatomic, readonly) MPFeedbackCommand *dislikeCommand;  //設定不喜歡 
@property (nonatomic, readonly) MPFeedbackCommand *bookmarkCommand;  //新增標籤

  設定的方式如下:

  MPRemoteCommandCenter *rcc = [MPRemoteCommandCenter sharedCommandCenter];
    //新增暫停監聽
   [rcc.pauseCommand addTarget:self action:@selector(playOrPauseEvent:)];

整體的程式碼如下:

//
//  ViewController.m
//  音效播放
//
//  Created by 珠珠 on 2019/10/31.
//  Copyright © 2019 珠珠. All rights reserved.
//

#import "ViewController.h"

#import <AVFoundation/AVFoundation.h>
#import <MediaPlayer/MediaPlayer.h>


@interface ViewController ()

@property (nonatomic,strong) AVAudioPlayer *player ;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //設定音樂的後臺播放,注意background mode中需要勾選上
    AVAudioSession *session = [AVAudioSession sharedInstance];
    [session setCategory:AVAudioSessionCategoryPlayback error:nil];

    //獲取資訊中心
    MPNowPlayingInfoCenter *center = [MPNowPlayingInfoCenter defaultCenter];
    //設定要鎖屏要顯示的基本資訊
    NSMutableDictionary *infoDic = [NSMutableDictionary dictionary];
    [infoDic setObject:@"泡沫" forKey:MPMediaItemPropertyAlbumTitle];
    [infoDic setObject:@"歌手" forKey:MPMediaItemPropertyArtist];
    [infoDic setObject:[[MPMediaItemArtwork alloc] initWithImage:[UIImage imageNamed:@"61149b0491243c749fc871e67550a7f6"]] forKey:MPMediaItemPropertyArtwork];
    [infoDic setObject:@"200" forKey:MPMediaItemPropertyPlaybackDuration];
    [infoDic setObject:@"歌詞" forKey:MPMediaItemPropertyTitle];
    //給資訊中心賦值
    center.nowPlayingInfo = infoDic;
    //新增遠端事件監聽
    NSString *version= [UIDevice currentDevice].systemVersion;
    if(version.doubleValue <=7.1) {
        //iOS版本7.1以下的建議使用這個方法
        [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
    }else{
        //iOS版本7.1以上的的建議使用這個方法
         [self addRemoteCommandCenter];
    }
}



#pragma mark - 基本播放操作
//開始播放
- (IBAction)player:(id)sender {
    [self.player play];
    
    UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
    [self.view addSubview:view];
}

//暫停播放
- (IBAction)pause:(id)sender {
    [self.player pause];
}

//停止播放
- (IBAction)stop:(id)sender {
    [self.player stop];
}

//前進5秒
- (IBAction)qianJin5s:(id)sender {
    self.player.currentTime += 5;
}

//後退5秒
- (IBAction)houTui5s:(id)sender {
    self.player.currentTime -= 5;
}

//2倍速度播放
- (IBAction)faster:(id)sender {
    self.player.rate = 2;
}

//播放一次
- (IBAction)playOnce:(id)sender {
    self.player.numberOfLoops = 0;
}

//播放3次
- (IBAction)playThirst:(id)sender {
    self.player.numberOfLoops = 2;
}

//迴圈播放
- (IBAction)playAllTheTime:(id)sender {
    self.player.numberOfLoops = -1;
}

//聽筒播放
- (IBAction)tingTongPlay:(id)sender {
    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:0 error:nil];
}

//揚聲器播放
- (IBAction)outSpeakerPlayer:(id)sender {
    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionDefaultToSpeaker error:nil];
}

#pragma mark - MPRemoteCommandCenter相關的方法
- (void)addRemoteCommandCenter {
    MPRemoteCommandCenter *rcc = [MPRemoteCommandCenter sharedCommandCenter];
    //新增暫停監聽
    [rcc.pauseCommand addTarget:self action:@selector(playOrPauseEvent:)];
    //新增播放監聽
    [rcc.playCommand addTarget:self action:@selector(playOrPauseEvent:)];
    //下一首
    [rcc.nextTrackCommand addTarget:self action:@selector(nextCommandEvent:)];
    //上一首
    [rcc.previousTrackCommand addTarget:self action:@selector(previousTrackCommand:)];
    //耳機暫停和播放的監聽
    [rcc.togglePlayPauseCommand addTarget:self action:@selector(togglePlayPauseCommand:)];
    //快進(如果同時設定了下一首和快進,那麼鎖屏下只會顯示快進的按鈕)
    [rcc.skipForwardCommand addTarget:self action:@selector(handleSkipForward:)];
    [rcc.skipForwardCommand setPreferredIntervals:@[@(20)]];    // 設定快進時間(最大 99)
    //快退(如果同時設定了下一首和後退,那麼鎖屏下只會顯示快退的按鈕)
    [rcc.skipBackwardCommand addTarget:self action:@selector(handleSkipBack:)];
    [rcc.skipBackwardCommand setPreferredIntervals:@[@20]];     // 設定快退時間(最大99)
    
//    [self feedbackCommand]
}


- (void)playOrPauseEvent:(MPRemoteCommand *)command
{
    NSLog(@"播放或者暫停");
    if (self.player.isPlaying) {
        [self.player pause];
    }else {
        [self.player play];
    }
}

- (void)nextCommandEvent:(MPRemoteCommand *)command
{
    NSLog(@"%@",@"下一曲");
}

- (void)previousTrackCommand:(MPRemoteCommand *)command
{
    NSLog(@"%@",@"上一曲");
}

- (void)togglePlayPauseCommand:(MPRemoteCommand *)command {
    NSLog(@"耳機的開始和暫停");
    if (self.player.isPlaying) {
        [self.player pause];
    }else {
        [self.player play];
    }
}

- (void)handleSkipForward:(MPRemoteCommand *)command
{
    NSLog(@"快進%@",command);
}

- (void)handleSkipBack:(MPRemoteCommand *)command
{
    NSLog(@" 快退%@",command);
}


-(void)feedbackCommand:(MPRemoteCommandCenter *)rcc
{
    MPFeedbackCommand *likeCommand = [rcc likeCommand];
    [likeCommand setEnabled:YES];
    [likeCommand setLocalizedTitle:@"I love it"];  // can leave this out for default
    [likeCommand addTarget:self action:@selector(likeEvent:)];
    
    MPFeedbackCommand *dislikeCommand = [rcc dislikeCommand];
    [dislikeCommand setEnabled:YES];
    [dislikeCommand setActive:YES];
    [dislikeCommand setLocalizedTitle:@"I hate it"]; // can leave this out for default
    [dislikeCommand addTarget:self action:@selector(dislikeEvent:)];
    
    BOOL userPreviouslyIndicatedThatTheyDislikedThisItemAndIStoredThat = YES;
    
    if (userPreviouslyIndicatedThatTheyDislikedThisItemAndIStoredThat) {
        [dislikeCommand setActive:YES];
    }
    
    MPFeedbackCommand *bookmarkCommand = [rcc bookmarkCommand];
    [bookmarkCommand setEnabled:YES];
    [bookmarkCommand addTarget:self action:@selector(bookmarkEvent:)];
}

-(void)dislikeEvent: (MPFeedbackCommandEvent *)feedbackEvent
{
    NSLog(@"Mark the item disliked");
}
-(void)likeEvent: (MPFeedbackCommandEvent *)feedbackEvent
{
    NSLog(@"Mark the item liked");
}
-(void)bookmarkEvent: (MPFeedbackCommandEvent *)feedbackEvent
{
    NSLog(@"Bookmark the item or playback position");
}


#pragma mark - 遠端事件的監聽:[[UIApplication sharedApplication] beginReceivingRemoteControlEvents]
- (void)remoteControlReceivedWithEvent:(UIEvent *)event {
    NSLog(@"---event.type = %ld", (long)event.subtype);
}


#pragma mark - 懶載入播放器
- (AVAudioPlayer *)player {
    if (!_player) {
        //獲取播放的路徑 paomo.mp3   2018-11-27 10_36_51 1.wav
        NSURL *path = [[NSBundle mainBundle] URLForResource:@"paomo.mp3" withExtension:nil];
        //根據路徑建立播放物件
        AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithContentsOfURL:path error:nil];

        //如果這個屬性不設定的話,那麼不能設定倍速播放的功能
        player.enableRate = YES;
        
        //準備播放
        [player prepareToPlay];
        _player = player;

    }
    return _player;
}

@end

另參考連結:http://www.cocoachina.com/articles/15767

from:https://www.cnblogs.com/lyz0925/p/11792667.html

文章乃參考、轉載其他部落格所得,僅供自己學習作筆記使用!!!