iOS7 以上监听音量键Tips

iOS7 以上监听音量键Tips

iOS7已经废弃 MPMusicPlayerController 这个类与方法 (还是能使用,但对于以后代码迭代,最好替换掉 ) , 如果需要控制系统音量,需要使用 MPVolumeView

以下是一些使用监听音量变化的Tips

需求:音量键拍照 && 拍照无声黑科技

1
2
//代码来看,MPVolumeView 是一个 UIView 的子类
@interface MPVolumeView : UIView <NSCoding>

设计思路:

镜头模块需要监测音量键,音量变化触发拍照功能,为此可以设置一个单例来监测

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
//标准单例初始化
+(MPVolumeObserver*) sharedInstance;
{
static MPVolumeObserver *instance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[MPVolumeObserver alloc] init];
});

return instance;
}

-(id)init
{
self = [super init];
if( self ){

/*
1.初始化一个MPVolumeView来接受系统音量调整的View(平时系统按音量键弹出来的东西)

2.将其添加到windows最上方(不能不添加...)

PS:其实view的大小与位置并不影响
*/

CGRect frame = CGRectMake(0, -100, 0, 0);
_volumeView = [[MPVolumeView alloc] initWithFrame:frame];
[[UIApplication sharedApplication].windows[0] addSubview:_volumeView];
isFirstInit = NO;
}
return self;
}

开始监测音量

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117

-(void) startObserve;
{


/*

坑点1:
移植项目时候,因为旧版里面,会使用Microphone录音,用音量键拍照时候不会弹系统音量弹框,但是新需求是用Mic的时候才用激活Microphone


Audiosession负责调节你的app和ios系统里的音频行为.一旦加载了audiosession你可以获得一个Audiosession的单例.你可以配置这个Audiosession来控制你的app的音频行为.例如:

当你的app播放声音的时候,你是希望其他正在播放声音的app静音还是混合两个app的声音?
你的app如何回应突发的打断,例如这时候闹铃突然响了?
你的app又该如何回应耳机口的拔插呢?
AuioSession的配置会影响你的app在运行中所有的音频活动,除了利用System Sounds Services API控制的音频.

你还可以利用AudioSession来检测你所用硬件的参数,例如声道和采样率.

你还可以随时激活或者停止你的audioSession,当你的app播放声音或者正在录音的时候,你必须确保AudioSession处于激活状态.

系统也有权利随时中断你的audioSession,例如,当你来电话的时候.当然,AudioSession提供了api来让你的app从这种中断中恢复.


如果不初始化 AVAudioSession .则用音量键调节时候,会弹系统音量框!!!!!!!!切记!(原来没有弹是因为调用了Mic,Mic可能自带AVAudioSession的创建)
*/

//iOS7 以下用这个
// AudioSessionInitialize(NULL, NULL, NULL, NULL);
// SInt32 process = kAudioSessionCategory_AmbientSound;
// AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(process), &process);
// AudioSessionSetActive(YES);


//iOS7以上
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:nil];
[[AVAudioSession sharedInstance] setActive:YES error:nil];



/*

遍历MPVolumeView,获得其中的Slider,Slider就是当前系统音量

*/
[[_volumeView subviews]enumerateObjectsUsingBlock:^(__kindof UIView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {

if ([obj isKindOfClass:[UISlider class]]) {
//需要send一下才不会获取0

/*

坑点2:
如果不设置这段代码,则获得出来的音量是0,多次测试后发现,如果之前已经调整过音量,则可以正常获得音量,猜测:需要调整过系统的才可以初始化Slider,才获得正确音量
这个方法模拟点击事件,则达到上面的要求

*/
[((UISlider*)obj) sendActionsForControlEvents:UIControlEventTouchUpInside];

//获得Slider音量大小
launchVolume = ((UISlider*)obj).value;

*stop = YES;
}

}];


//iOS7以下设置音量和获取音量方法
// launchVolume = [[MPMusicPlayerController applicationMusicPlayer] volume];

//不给调到0声音
launchVolume = launchVolume == 0 ? 0.05 : launchVolume;
launchVolume = launchVolume == 1 ? 0.95 : launchVolume;
if (launchVolume == 0.05 || launchVolume == 0.95) {
// [[MPMusicPlayerController applicationMusicPlayer] setVolume:launchVolume];

//New.
[[_volumeView subviews]enumerateObjectsUsingBlock:^(__kindof UIView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {

if ([obj isKindOfClass:[UISlider class]]) {
//需要send一下才不会获取0
// [((UISlider*)obj) sendActionsForControlEvents:UIControlEventTouchUpInside];

//获得Slider音量大小
((UISlider*)obj).value = launchVolume;

*stop = YES;
}

}];



}



[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(suspendObserveVolumeChangeEvents:)
name:UIApplicationWillResignActiveNotification // -> Inactive
object:nil];

[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(resumeObserveVolumeButtonEvents:)
name:UIApplicationDidBecomeActiveNotification // <- Active
object:nil];

//AVSystemController_SystemVolumeDidChangeNotification
//SystemVolumeDidChange
//监听系统音量
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(volumeChangeNotification:)
name:@"SystemVolumeDidChange" object:nil];
}


以上方法能检测出系统音量

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

-(void) volumeChangeNotification:(NSNotification *) no
{

NSLog(@"Volume Change!!");

static id sender = nil;
if (sender == nil && no.object) {
sender = no.object;
}

if (no.object != sender || [[no.userInfo objectForKey:@"AudioVolume"] floatValue] == launchVolume) {
return;
}


/*

坑点3:
返回的通知字典里面,有一个key记录着系统音量通知变化的原因,只有 ExplicitVolumeChange 才代表音量变化,插拔耳机都会触发音量变化通知的!!!

*/
//如果检测出抽插耳机,则不需要音量监控
if (![[no.userInfo objectForKey:@"AudioVolumeChangeReason"] isEqualToString:@"ExplicitVolumeChange"]) {
return;
}

// [[MPMusicPlayerController applicationMusicPlayer] setVolume:launchVolume];


/*

坑点4:
不能通过_volumeView 重新设置会音量,因为按了,声音会变大一点在变回原来的音量,但是并不满足需求
通过研究,只能通过新建一个MPVolumeView,来设置,则不会有音量变化

*/
//New.
MPVolumeView *volumeView= [[MPVolumeView alloc] initWithFrame:CGRectMake(-2000.0f, -2000.0f, 0.0f, 0.0f)];
volumeView.alpha = 0.10f;
volumeView.userInteractionEnabled = NO;
NSArray *windows = [UIApplication sharedApplication].windows;
[[windows firstObject] addSubview:volumeView];
[[volumeView subviews]enumerateObjectsUsingBlock:^(__kindof UIView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if ([obj isKindOfClass:[UISlider class]]) {
//第一次获取到的launchVolume为0,按音量键拍照的时候设置为0,会导致拍照后的音量为0
((UISlider*)obj).value = launchVolume;
*stop = YES;
}
}];
[volumeView removeFromSuperview];



if ([self.delegate respondsToSelector:@selector(volumeButtonDidClick:)] ) {
[self.delegate volumeButtonDidClick:self];
}


}


当然需要stop监察

1
2
3
4
5
6
7
8
9
10
11
-(void)stopObserveVolumeChangeEvents
{

[[NSNotificationCenter defaultCenter] removeObserver:self];

// AudioSessionRemovePropertyListenerWithUserData(kAudioSessionProperty_CurrentHardwareOutputVolume, NULL, (__bridge void *)(self));
// AudioSessionSetActive(NO);



}

iOS7 以上监听音量键Tips

https://swlfigo.github.io/posts/aeb8/

Author

Sylar

Posted on

2019-04-28

Updated on

2020-09-21

Licensed under

Comments