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及以下可用)
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.锁屏下要显示歌曲信息的设置
从上文中,已经可以知道,用
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