【转】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

文章乃参考、转载其他博客所得,仅供自己学习作笔记使用!!!
原文地址:https://www.cnblogs.com/xuan52rock/p/15020394.html