在默认环境下App被切换到后台时,音乐的就停止播放了,但音乐类App的一般都会需要在后台继续播放,这样用户就可以一边听音乐,一边操作其他的App。对于这种情况我们可以对App做一些简单的配置,实现后台播放功能。当app切换到后台,用户就无法控制和查看app当前播放歌曲了。这个对于用户来说并不是很友好。既然是后台播放,那么就应该提供便捷的播放控制方式。iOS系统已经预留了接口,允许开发者在锁屏界面显示播放歌曲信息(以下称为锁屏封面),以及在底部菜单栏提供播放控制器。下面我们就来给App添加这些功能吧。
一、后台播放
设置App的plist,使app可以在后台播放音乐。
myApp-Info.plist中添加UIBackgroundModes键值,添加子键值为audio。
然后再程序中添加入下代码:
1
2
3
|
AVAudioSession
*session
=
[
AVAudioSession
sharedInstance
]
;
[
session
setActive
:YES
error
:nil
]
;
[
session
setCategory
:AVAudioSessionCategoryPlayback
error
:nil
]
;
|
二、添加播放控制器(Remote Control Events)
首先我们要告诉系统,我要接受系统的播放控制消息,这样系统才会给我们发送播放控制命令。流程是这样的:
App启动 -> 告诉系统我需要接受播放控制消息 -> 等待 -> 用户点击系统播放控制器按钮 -> 系统传递消息给App -> 我们接受到消息,做出相应的响应。
想要接收播放控制消息,我们必须要做三件事:
- 成为Frist Responder
- 请求系统,要求开始监听播放控制消息(Remote Control Events)
- 开始播放音频。
请注意第三点,我们的App必须在开始播放音频后,才能收到控制消息。否则,即使你满足了前两点,也无法接收到控制消息。
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
32
33
34
35
36
37
38
|
//AppDelegate.m
-
(
BOOL
)
application
:
(
UIApplication
*
)
application
didFinishLaunchingWithOptions
:
(
NSDictionary
*
)
launchOptions
{
//...
//告诉系统,我们要接受远程控制事件
[
[
UIApplication
sharedApplication
]
beginReceivingRemoteControlEvents
]
;
[
self
becomeFirstResponder
]
;
}
-
(
BOOL
)
canBecomeFirstResponder
{
return
YES
;
}
//响应远程音乐播放控制消息
-
(
void
)
remoteControlReceivedWithEvent
:
(
UIEvent
*
)
receivedEvent
{
if
(
receivedEvent
.
type
==
UIEventTypeRemoteControl
)
{
switch
(
receivedEvent
.
subtype
)
{
case
UIEventSubtypeRemoteControlTogglePlayPause
:
[
[
PlayController
sharedInstance
]
pause
]
;
NSLog
(
@"RemoteControlEvents: pause"
)
;
break
;
case
UIEventSubtypeRemoteControlNextTrack
:
[
[
PlayController
sharedInstance
]
playModeNext
]
;
NSLog
(
@"RemoteControlEvents: playModeNext"
)
;
break
;
case
UIEventSubtypeRemoteControlPreviousTrack
:
[
[
PlayController
sharedInstance
]
playPrev
]
;
NSLog
(
@"RemoteControlEvents: playPrev"
)
;
break
;
default
:
break
;
}
}
}
|
播放音频的代码,这里给出一段简单的示例:
1
2
3
4
5
6
7
8
9
10
|
-
(
void
)
playBtnClicked
{
NSError
*error
=
nil
;
NSString
*path
=
[
[
NSBundle
mainBundle
]
pathForResource
:
@"music"
ofType
:
@"mp3"
]
;
AVAudioPlayer
*player
=
[
[
AVAudioPlayer
alloc
]
initWithContentsOfURL
:
[
NSURL
URLWithString
:path
]
error
:
&
error
]
;
if
(
error
)
{
NSLog
(
@"Error:%@"
,
[
error
localizedDescription
]
)
;
}
[
player
play
]
;
}
|
在开始播放音频后,使用耳机线控的播放暂停等按键,或者锁屏封面上的播放控制按键,就能够收到控制消息了。
关于耳机线控的一点说明
苹果耳机的线控上有三个按钮:加号,中部,减号。其中加号和减号是用于控制音量,这两个按钮点击是收不到消息的——UIEventSubtype没有音量改变的事件类型。而中部按钮的点击,是可以收到消息的,按一下是播放/暂停切换,快按两下是播放下一首,快按三下是播放上一首,快按两下并摁住是快进,快按三下并摁住是快退。
三、在锁屏界面显示播放歌曲信息
代码如下,其实就是设置一个全局变量的值,当系统处于音乐播放状态时,锁屏界面就会将NowPlayingInfo中的信息展示出来。可惜的是,这里的定制性不是太强,例如歌曲图片无法平铺整个屏幕大小,根据我的测试,歌曲图片在320×320时,可以完整显示在屏幕中央位置,两侧不会留下黑边。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
-
(
void
)
setLockScreenNowPlayingInfo
{
//更新锁屏时的歌曲信息
if
(
NSClassFromString
(
@"MPNowPlayingInfoCenter"
)
)
{
NSMutableDictionary
*dict
=
[
[
NSMutableDictionary
alloc
]
init
]
;
[
dict
setObject
:
@"歌曲名"
forKey
:MPMediaItemPropertyTitle
]
;
[
dict
setObject
:
@"演唱者"
forKey
:MPMediaItemPropertyArtist
]
;
[
dict
setObject
:
@"专辑名"
forKey
:MPMediaItemPropertyAlbumTitle
]
;
UIImage
*newImage
=
[
UIImage
imageWithNamed
:
@"歌曲封面图片"
]
;
[
dict
setObject
:
[
[
[
MPMediaItemArtwork
alloc
]
initWithImage
:newImage
]
autorelease
]
forKey
:MPMediaItemPropertyArtwork
]
;
[
[
MPNowPlayingInfoCenter
defaultCenter
]
setNowPlayingInfo
:dict
]
;
}
}
|
经过了如上配置后,程序应该就能够正常显示了,enjoy~