OC-音樂播放器-鎖屏處理


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

 

 

 

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

 

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

 

實現的原理:

(1)獲取鎖屏歌曲信息中心:MPNowPlayingInfoCenter

(2)設置鎖屏下要顯示的歌曲的信息

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

 

1.MPNowPlayingInfoCenter簡要說明

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

// -----------------------------------------------------------------------------
// 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.

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

MPNowPlayingInfoCenter(播放信息中心)為應用程序提供設置當前正在播放的信息的接口;

  此信息將顯示在正在播放信息類型調用的任何位置,例如鎖屏下或者應用程序切換中;

  正在播放的信息字典包含一組正在播放項的元數據屬性,這些屬性常量列表在<MediaPlayer/MPMediaItem.h>有提供;

  這些屬性目前提供的包括:

   MPMediaItemPropertyAlbumTitle (標題)

   MPMediaItemPropertyAlbumTrackCount(專輯歌曲數)

   MPMediaItemPropertyAlbumTrackNumber (專輯歌曲編號)

   MPMediaItemPropertyArtist (藝術家/歌手)

   MPMediaItemPropertyArtwork (封面圖片  MPMediaItemArtwork 類型)

   MPMediaItemPropertyComposer (作曲)

   MPMediaItemPropertyDiscCount (專輯數)

   MPMediaItemPropertyDiscNumber (專輯編號)

   MPMediaItemPropertyGenre (類型\流派)

   MPMediaItemPropertyPersistentID (唯一標識符)

  MPMediaItemPropertyPlaybackDuration (歌曲時長)

   MPMediaItemPropertyTitle (歌曲名稱)

  此外,音樂播放必須支持后台播放的功能。

  

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

/// 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及以下可用)
Name Type meaning
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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM