iOS音频播放 (八):NowPlayingCenter和RemoteControl
2015-09-06 18:49
573 查看
文章转自:http://msching.github.io/blog/2014/11/06/audio-in-ios-8/
距离上一篇博文发布已经有一个月多的时间了,在这其间我一直忙于筹办婚礼以至于这篇博文一直拖到了现在。
在之前一到六篇中我对iOS下的音频播放流程进行了阐述,在第七篇中介绍了如何播放iPod
Lib中的歌曲,至此有关音频播放的话题就已经完结了,在这篇里我将会讲到的
锁频界面上所显示的歌曲播放信息和图片
iOS7之后控制中心上显示的歌曲播放信息
iOS7之前双击home键后出现的进程中向左滑动出现的歌曲播放信息
AppleTV,AirPlay中显示的播放信息
车载系统中显示的播放信息
这些信息的显示都由
使用也同样简单,首先
上面这些属性大多比较浅显易懂,基本上按照字面上的意思去理解就可以了,需要稍微解释以下的是
另外一些附加属性被定义在
其中常用的是
这里需要解释的是,
所以每次播放暂停和继续都需要更新
依照我自己的经验下面几个情况下刷新
当前播放歌曲进度被拖动时
当前播放的歌曲变化时
播放暂停或者恢复时
当前播放歌曲的信息发生变化时(例如Artwork,duration等)
在刷新时可以适当的通过判断app是否active来决定是否必须刷新以减少刷新次数。
锁屏界面双击Home键后出现的播放操作区域
iOS7之后控制中心的播放操作区域
iOS7之前双击home键后出现的进程中向左滑动出现的播放操作区域
AppleTV,AirPlay中显示的播放操作区域
耳机线控
车载系统的设置
当
responder,如果first responder不处理这个事件的话那么事件就会沿着responder chain继续转发。关于responder chain的相关内容可以查看这里。
从responder chain文档看来如果之前的所有responder全部不响应
chain的最末端,在
![](http://msching.github.io/images/iOS-audio/responder%20chain.jpg)
然后找到工程中的
在main中调用了
我们需要做的就是给
这样就成功实现了自己的
接受者必须能够成为first responder
必须显示地声明接收
你的app必须是
对于第一条就是要在自己的
第二条是要求显示地调用
第三条就是要求占据NowPlayingCenter,这个之前已经提到过了。
满足三个条件后可以在
Remote
Control Events
Cocoa Responder Chain
原创文章,版权声明:自由转载-非商用-非衍生-保持署名 | Creative
Commons BY-NC-ND 3.0
距离上一篇博文发布已经有一个月多的时间了,在这其间我一直忙于筹办婚礼以至于这篇博文一直拖到了现在。
在之前一到六篇中我对iOS下的音频播放流程进行了阐述,在第七篇中介绍了如何播放iPod
Lib中的歌曲,至此有关音频播放的话题就已经完结了,在这篇里我将会讲到的
NowPlayingCenter和
RemoteControl这两个玩意本身和整个播放流程并没有什么关系,但它们可以让音频播放在iOS系统上获得更加好的用户体验。
NowPlayingCenter
NowPlayingCenter能够显示当前正在播放的歌曲信息,它可以控制的范围包括:
锁频界面上所显示的歌曲播放信息和图片
iOS7之后控制中心上显示的歌曲播放信息
iOS7之前双击home键后出现的进程中向左滑动出现的歌曲播放信息
AppleTV,AirPlay中显示的播放信息
车载系统中显示的播放信息
这些信息的显示都由
MPNowPlayingInfoCenter类来控制,这个类的定义非常简单:
1 2 3 4 5 6 7 8 9 10 11 | [code]MP_EXTERN_CLASS_***AILABLE(5_0) @interface MPNowPlayingInfoCenter : NSObject // 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 (copy) NSDictionary *nowPlayingInfo; @end |
#import <MediaPlayer/MPNowPlayingInfoCenter.h>然后调用
MPNowPlayingInfoCenter的单例方法获取实例,再把需要显示的信息组织成Dictionary并赋值给
nowPlayingInfo属性就完成了。
nowPlayingInfo中一些常用属性被定义在
<MediaPlayer/MPMediaItem.h>中
1 2 3 4 5 6 7 8 9 10 1112 | [code]MPMediaItemPropertyAlbumTitle //NSString MPMediaItemPropertyAlbumTrackCount //NSNumber of NSUInteger MPMediaItemPropertyAlbumTrackNumber //NSNumber of NSUInteger MPMediaItemPropertyArtist //NSString MPMediaItemPropertyArtwork //MPMediaItemArtwork MPMediaItemPropertyComposer //NSString MPMediaItemPropertyDiscCount //NSNumber of NSUInteger MPMediaItemPropertyDiscNumber //NSNumber of NSUInteger MPMediaItemPropertyGenre //NSString MPMediaItemPropertyPersistentID //NSNumber of uint64_t MPMediaItemPropertyPlaybackDuration //NSNumber of NSTimeInterval MPMediaItemPropertyTitle //NSString |
MPMediaItemPropertyArtwork。这个属性表示的是锁屏界面或者AirPlay中显示的歌曲封面图,
MPMediaItemArtwork类可以由
UIImage类进行初始化。
1 2 3 4 5 6 7 8 9 10 1112 | [code]MP_EXTERN_CLASS_***AILABLE(3_0) @interface MPMediaItemArtwork : NSObject // Initializes an MPMediaItemArtwork instance with the given full-size image. // The crop rect of the image is assumed to be equal to the bounds of the // image as defined by the image's size in points, i.e. tightly cropped. - (instancetype)initWithImage:(UIImage *)image NS_DESIGNATED_INITIALIZER NS_***AILABLE_IOS(5_0); // Returns the artwork image for an item at a given size (in points). - (UIImage *)imageWithSize:(CGSize)size; @property (nonatomic, readonly) CGRect bounds; // The bounds of the full size image (in points). @property (nonatomic, readonly) CGRect imageCropRect; // The actual content area of the artwork, in the bounds of the full size image (in points). @end |
<MediaPlayer/MPNowPlayingInfoCenter.h>中
1 2 3 4 5 6 7 8 9 10 1112 | [code]// The elapsed time of the now playing item, in seconds. // Note the elapsed time will be automatically extrapolated from the previously // provided elapsed time and playback rate, so updating this property frequently // is not required (or recommended.) MP_EXTERN NSString *const MPNowPlayingInfoPropertyElapsedPlaybackTime NS_***AILABLE_IOS(5_0); // NSNumber (double) // The playback rate of the now playing item, with 1.0 representing normal // playback. For example, 2.0 would represent playback at twice the normal rate. // If not specified, assumed to be 1.0. MP_EXTERN NSString *const MPNowPlayingInfoPropertyPlaybackRate NS_***AILABLE_IOS(5_0); // NSNumber (double) // The "default" playback rate of the now playing item. You should set this // property if your app is playing a media item at a rate other than 1.0 in a // default playback state. e.g., if you are playing back content at a rate of // 2.0 and your playback state is not fast-forwarding, then the default // playback rate should also be 2.0. Conversely, if you are playing back content // at a normal rate (1.0) but the user is fast-forwarding your content at a rate // greater than 1.0, then the default playback rate should be set to 1.0. MP_EXTERN NSString *const MPNowPlayingInfoPropertyDefaultPlaybackRate NS_***AILABLE_IOS(8_0); // NSNumber (double) // The index of the now playing item in the application's playback queue. // Note that the queue uses zero-based indexing, so the index of the first item // would be 0 if the item should be displayed as "item 1 of 10". MP_EXTERN NSString *const MPNowPlayingInfoPropertyPlaybackQueueIndex NS_***AILABLE_IOS(5_0); // NSNumber (NSUInteger) // The total number of items in the application's playback queue. MP_EXTERN NSString *const MPNowPlayingInfoPropertyPlaybackQueueCount NS_***AILABLE_IOS(5_0); // NSNumber (NSUInteger) // The chapter currently being played. Note that this is zero-based. MP_EXTERN NSString *const MPNowPlayingInfoPropertyChapterNumber NS_***AILABLE_IOS(5_0); // NSNumber (NSUInteger) // The total number of chapters in the now playing item. MP_EXTERN NSString *const MPNowPlayingInfoPropertyChapterCount NS_***AILABLE_IOS(5_0); // NSNumber (NSUInteger) |
MPNowPlayingInfoPropertyElapsedPlaybackTime和
MPNowPlayingInfoPropertyPlaybackRate:
MPNowPlayingInfoPropertyElapsedPlaybackTime表示已经播放的时间,用这个属性可以让
NowPlayingCenter显示播放进度;
MPNowPlayingInfoPropertyPlaybackRate表示播放速率。通常情况下播放速率为1.0,即真是时间的1秒对应播放时间中的1秒;
这里需要解释的是,
NowPlayingCenter中的进度刷新并不是由app不停的更新
nowPlayingInfo来做的,而是根据app传入的
ElapsedPlaybackTime和
PlaybackRate进行自动刷新。例如传入ElapsedPlaybackTime=120s,PlaybackRate=1.0,那么
NowPlayingCenter会显示2:00并且在接下来的时间中每一秒把进度加1秒并刷新显示。如果需要暂停进度,传入PlaybackRate=0.0即可。
所以每次播放暂停和继续都需要更新
NowPlayingCenter并正确设置
ElapsedPlaybackTime和
PlaybackRate否则
NowPlayingCenter中的播放进度无法正常显示。
NowPlayingCenter的刷新时机
频繁的刷新NowPlayingCenter并不可取,特别是在有Artwork的情况下。所以需要在合适的时候进行刷新。
依照我自己的经验下面几个情况下刷新
NowPlayingCenter比较合适:
当前播放歌曲进度被拖动时
当前播放的歌曲变化时
播放暂停或者恢复时
当前播放歌曲的信息发生变化时(例如Artwork,duration等)
在刷新时可以适当的通过判断app是否active来决定是否必须刷新以减少刷新次数。
MPMediaItemPropertyArtwork
这是一个非常有用的属性,我们可以利用歌曲的封面图来合成一些图片借此达到美化锁屏界面或者显示锁屏歌词。RemoteControl
RemoteComtrol可以用来在不打开app的情况下控制app中的多媒体播放行为,涉及的内容主要包括:
锁屏界面双击Home键后出现的播放操作区域
iOS7之后控制中心的播放操作区域
iOS7之前双击home键后出现的进程中向左滑动出现的播放操作区域
AppleTV,AirPlay中显示的播放操作区域
耳机线控
车载系统的设置
在何处处理RemoteComtrol
根据官方文档的描述:If your app plays audio or video content, you might want it to respond to remote control events that originate from either transport controls or external accessories. (External accessories must conform to Apple-provided specifications.) iOS converts commands into UIEvent objects and delivers the events to an app. The app sends them to the first responder and, if the first responder doesn’t handle them, they travel up the responder chain.
当
RemoteComtrol事件产生时,iOS会以
UIEvent的形式发送给app,app会首先转发到first
responder,如果first responder不处理这个事件的话那么事件就会沿着responder chain继续转发。关于responder chain的相关内容可以查看这里。
从responder chain文档看来如果之前的所有responder全部不响应
RemoteComtrol事件的话,最终事件会被转发给Application(如图)。所以我们知道作为responder
chain的最末端,在
UIApplication中实现
RemoteComtrol的处理是最为合理的,而并非在UIWindow中或者AppDelegate中。
![](http://msching.github.io/images/iOS-audio/responder%20chain.jpg)
实现自己的UIApplication
首先新建一个UIApplication的子类
1 2 3 4 5 | [code]#import <UIKit/UIKit.h> @interface MyApplication : UIApplication @end |
main.m,可以看到代码如下:
1 2 3 4 56 | [code]int main(int argc, char * argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } } |
UIApplicationMain方法
1 2 3 | [code]// If nil is specified for principalClassName, the value for NSPrincipalClass from the Info.plist is used. If there is no // NSPrincipalClass key specified, the UIApplication class is used. The delegate class will be instantiated using init. UIKIT_EXTERN int UIApplicationMain(int argc, char *argv[], NSString *principalClassName, NSString *delegateClassName); |
UIApplicationMain方法的第三个参数传入我们的application类名,如下:
1 2 3 4 56 | [code]#import <UIKit/UIKit.h> #import "AppDelegate.h" #import "MyApplication.h" int main(int argc, char * argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, NSStringFromClass([MyApplication class]), NSStringFromClass([AppDelegate class])); } } |
UIApplication.
处理RemoteComtrol
了解了应该在何处处理RemoteComtrol事件之后,再来看下官方文档中描述的三个必要条件:
接受者必须能够成为first responder
必须显示地声明接收
RemoteComtrol事件
你的app必须是
Now Playingapp
对于第一条就是要在自己的
UIApplication中实现
canBecomeFirstResponder方法:
1 2 3 4 56 | [code]#import "MyApplication.h" @implementation MyApplication - (BOOL)canBecomeFirstResponder { return YES; } @end |
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents],调用的实际一般是在播放开始时;
第三条就是要求占据NowPlayingCenter,这个之前已经提到过了。
满足三个条件后可以在
UIApplication中实现处理
RemoteComtrol事件的方法,根据不同的事件实现不同的操作即可。
1 2 3 4 5 6 7 8 9 10 1112 | [code]#import "MyApplication.h" @implementation MyApplication - (BOOL)canBecomeFirstResponder { return YES; } - (void)remoteControlReceivedWithEvent:(UIEvent *)event { switch (event.subtype) { case UIEventSubtypeRemoteControlPlay: //play break; case UIEventSubtypeRemoteControlPause: //pause break; case UIEventSubtypeRemoteControlStop: //stop break; default: break; } } @end |
示例代码
git上有一个关于remotecontrol的小工程供大家参考ios-audio-remote-control后记
到本篇为止iOS的音频播放话题基本上算是完结了。接下来我会在空余时间去研究一下iOS 8中新加入的***AudioEngine,其功能涵盖播放、录音、混音、音效处理,看上去十分强大,从接口的定义上看像是对
AudioUnit的高层封装,当研究有了一定的成果之后也会以博文的形式分享出来。
参考资料
MPNowPlayingInfoCenterRemote
Control Events
Cocoa Responder Chain
原创文章,版权声明:自由转载-非商用-非衍生-保持署名 | Creative
Commons BY-NC-ND 3.0
相关文章推荐
- iOS音频播放 (七):播放iPod Library中的歌曲
- iOS音频播放 (六):简单的音频播放器实现
- 为个人或企业用户创建 iOS 描述文件
- iOS音频播放 (四):AudioFile
- iOS音频播放 (三):AudioFileStream
- iOS音频播放 (二):AudioSession
- iOS音频播放 (一):概述
- ios 避免navigationcontroller出现时scrollview内容被resize
- ios 转json字符串
- iOS 开发经典博客
- IOS 实现边滑动边缩放的类似qq主界面的页面切换功能
- ios 排序
- IOS第18天(10,核心动画-转盘,自定义buton,旋转动画)
- iOS应用内部切换语言,不跟随系统
- iOS开发中ViewController切换动画的制作
- iOS开发常用的几大工具
- iOS开发常用的几大工具
- iOS断点下载的小问题
- IOS第18天(9,核心动画-动画组)
- iOS--设置Launch Image 启动图片