OC-音乐播放器-锁屏处理

QQ音乐播放的过程中,锁屏状态下的效果如下:

也就是说,QQ音乐播放过程中,添加锁屏远程事件的监听。

本文只记录本人知道的小知识点,不提供完整的代码。

实现的原理:

(1)获取锁屏歌曲信息中心:MPNowPlayingInfoCenter

(2)设置锁屏下要显示的歌曲的信息

(3)启动远程事件的监听

1.MPNowPlayingInfoCenter简要说明

(1)官方文档对MPNowPlayingInfoCenter的解说如下:

<span style="color:#008000">// -----------------------------------------------------------------------------
// 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.
</span>

 上面那段话大体的意思如下:

   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及以下可用)

NameTypemeaning
MPMediaItemPropertyAlbumTitleNSString专辑歌曲数
MPMediaItemPropertyAlbumTrackCountNSNumber of NSUInteger专辑歌曲数
MPMediaItemPropertyAlbumTrackNumberNSNumber of NSUInteger艺术家/歌手
MPMediaItemPropertyArtistNSString艺术家/歌手
MPMediaItemPropertyArtworkMPMediaItemArtwork封面图片 MPMediaItemArtwork类型
MPMediaItemPropertyComposerNSString作曲
MPMediaItemPropertyDiscCountNSNumber of NSUInteger专辑数
MPMediaItemPropertyDiscNumber NSNumber of NSUInteger专辑编号
MPMediaItemPropertyGenreNSString类型/流派
MPMediaItemPropertyPersistentIDNSNumber of uint64_t唯一标识符
MPMediaItemPropertyPlaybackDurationNSNumber of NSTimeInterval歌曲时长 NSNumber类型
MPMediaItemPropertyTitleNSString歌曲名称
MPNowPlayingInfoPropertyElapsedPlaybackTimeNSNumber (double)在播资源的时间流逝,s为单位。流逝时间会从播放时间和播放速率中自动计算,不合适频繁得更新
MPNowPlayingInfoPropertyPlaybackRateNSNumber (double)在播资源的速率(保持与APP内播放器的速率一致)
MPNowPlayingInfoPropertyDefaultPlaybackRateNSNumber (double)在播资源的“默认”播放速率,当你的APP需要播放资源的播放速率默认都是大于1的,那么就应该使用这属性
MPNowPlayingInfoPropertyPlaybackQueueIndexNSNumber (NSUInteger)应用重放队列中,当前播放项的索引。注意索引值从0开始
MPNowPlayingInfoPropertyPlaybackQueueCountNSNumber (NSUInteger)应用重放队列的总资源数目
MPNowPlayingInfoPropertyChapterNumberNSNumber (NSUInteger)这在播放的部分,索引值从0开始
MPNowPlayingInfoPropertyChapterCountNSNumber (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,无需更高的精度要求。如:当字幕开始滚动时,这个电影可能被用户期望开始播放(由字幕驱动播放进度)
MPNowPlayingInfoPropertyMediaTypeNSNumber (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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值