如何设置与系统音量(iOS设备音量物理按键)分开的应用程序音量?
我们的应用程序能够在无线扬声器上播放音乐。 该应用程序的function之一是通过按音量+ /音量 – iPhone上的硬键来改变扬声器的音量。
这背后的逻辑是获取系统的音量值并将其发送给扬声器。
但问题是这个函数影响系统音量。 有没有办法避免在应用程序内按下音量键时调整系统音量?
这是我用来在每次印刷中获得系统音量的代码:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if ([keyPath isEqual:@"outputVolume"]) { CGFloat phoneVolume = [[AVAudioSession sharedInstance] outputVolume]; NSInteger volume = 100 * phoneVolume; [self onHardKeyVolumeChange:volume]; } }
谢谢。
以下是我所做的:
- 获取当前的系统卷。
- 隐藏音量调整popup视图。
- 添加观察者以更改系统音量。
- 将系统音量恢复到您从观察者收到的每个callback中获得的音量(在步骤1中)。
我会详细解释每一步。
第1步 – 获取当前的系统音量
初始化卷的代码:
- (void)initializeSystemVolume { _originalSystemVolume = [[AVAudioSession sharedInstance] outputVolume]; _currentSystemVolume = _originalSystemVolume; if(_currentSystemVolume == 0.0) { _currentSystemVolume = 0.0625; } else if(_currentSystemVolume == 1.0) { _currentSystemVolume = 0.9375; } [self setSystemVolume:_currentSystemVolume]; }
_originalSystemVolume – 这是进入应用程序时的系统音量。
_currentSystemVolume – 这也可以是原来的音量相同,但这可以改变,而originalSystemVolume应该保持不变。
从if else语句中可以看出,我将首先检查当前系统音量是否处于最大值(1.0)或最小值(0.0)。 我为什么要这样做?
因为从我的实验中,我注意到音量按键的callback只有在系统音量改变的情况下才能进行。 所以如果当前系统音量在最小值(0.0),并且你仍然按下音量 – button。 不会有callback。 那么在这种情况下,你永远不会确定音量 – 按键状态。
所以这就是为什么我需要改变当前系统音量到一个更高的音量(0.0625),如果它是最低的,或者如果它的最大值改变到较低的音量(0.9375),这样我们仍然能够得到callback从系统。 现在,为什么0.0625和0.9375?
那么,其实我只是想把它设置到最接近的可能值。 如果你会注意到,iOS的音量分成16个级别,每个级别增加0.0625。 0.0是静音模式,1.0是峰值音量。
第2步 – 隐藏音量调整popup视图
隐藏音量popup窗口的代码:
- (void)moveVolumeChangeNotifSliderOffTheScreen { CGRect frame = CGRectMake(0, -100, 10, 0); MPVolumeView *volumeView = [[MPVolumeView alloc] initWithFrame:frame]; [volumeView sizeToFit]; [[[[UIApplication sharedApplication] windows] objectAtIndex:0] addSubview:volumeView]; }
由于我们不会影响系统音量,所以我们不应该显示popup窗口。
这个代码的信用转到另一个人。 对不起,我忘了我在哪里,但我没有写。
第3步 – 添加观察员以更改系统音量。
现在,我们应该每按一下按键,听一下系统音量的变化,然后我们可以使用callback返回的值来确定哪个音量键被按下。
设置观察者的代码:
- (void)setVolumeChangeObserver { [self removeVolumeChangeObserver]; [[AVAudioSession sharedInstance] setActive:YES error:nil]; [[AVAudioSession sharedInstance] addObserver:self forKeyPath:@"outputVolume" options:0 context:nil]; }
删除观察者代码:
- (void)removeVolumeChangeObserver { @try { [[AVAudioSession sharedInstance] removeObserver:self forKeyPath:@"outputVolume"]; } @catch(id anException) { } }
代码为callback:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if ([keyPath isEqual:@"outputVolume"]) { if([[AVAudioSession sharedInstance] outputVolume] < _currentSystemVolume) { NSLog(@"Volume key down"); //your code when volume key down is pressed. } else if([[AVAudioSession sharedInstance] outputVolume] > _currentSystemVolume) { NSLog(@"Volume key up"); //your code when volume key up is pressed. } [self removeVolumeChangeObserver]; [self setSystemVolume:_currentSystemVolume]; [self setVolumeChangeObserver]; } }
从代码中可以看出,我们在按键时使用outputVolume,并将其与我们之前设置的_currentSystemVolume进行比较,我们可以确定是按下音量+还是按下音量。
在分析哪个按键被按下后,我们应该立即将系统音量设置回原来的状态,以便在应用程序中按下音量按键不会影响系统音量。
重要提示 :在设置系统音量之前,您必须先移除观察者。 为什么? 因为如果你不这样做,一旦你设置了系统音量,这个callback就会重新进行,当这个情况发生时, setSystemVolume
将被再次调用,然后再次进行callback,那么你的setSystemVolume
将被再次调用,然后一遍又一遍…然后你会在这个上创build一个死锁。 通过删除观察者,不会做callback。
第4步 – 设置系统音量
现在,我们如何设置系统音量呢?
系统音量设定代码:
- (void)setSystemVolume:(CGFloat)volume { if(_volumeView == nil) { _volumeView = [[SystemVolumeView alloc] init]; } _volumeView.getVolumeSlider.value = volume; }
_volumeView是我做的类SystemVolumeView的一个实例,它扩展了MPVolumeView以检索MPVolumeView的UISlider。 MPVolumeView是调整系统音量(媒体音量)时popup的视图。
SystemVolumeView代码:
SystemVolumeView.h
#import <MediaPlayer/MediaPlayer.h> @interface SystemVolumeView : MPVolumeView - (UISlider *)getVolumeSlider; @end
SystemVolumeView.m
#import <AVFoundation/AVFoundation.h> #import "SystemVolumeView.h" @interface SystemVolumeView () @property UISlider *systemVolumeSlider; @end @implementation SystemVolumeView - (UISlider *)getVolumeSlider { if(_systemVolumeSlider != nil) { return _systemVolumeSlider; } self.showsRouteButton = false; self.showsVolumeSlider = false; self.hidden = true; for(UIView *subview in self.subviews) { if([subview isKindOfClass:[UISlider class]]) { _systemVolumeSlider = (UISlider *)subview; _systemVolumeSlider.continuous = true; return _systemVolumeSlider; } } return nil; } @end
此代码的信用转到此链接中接受的答案。 我只是把它翻译成Objective-C。
从上面的代码可以看出,你可以通过调用getVolumeSlider.value = yourDesiredVolume
来设置系统卷。 yourDesiredVolume应该只在0 – 1的范围内。
好了,毕竟,你应该对这些工作有一个想法。
现在,您可能注意到我们没有使用_originalSystemVolume
。
这是为了什么。 想象一下,如果系统的音量初始设置为静音,那么我们将其设置为更高的值,以使所有的function正常工作? 现在,一旦应用程序进入后台,我们应该把系统音量恢复到原来的水平。 在这种情况下,我们会在应用程序退出活动时执行此操作。
- (void)applicationWillResignActive:(UIApplication *)application { [self restoreSystemVolume]; }
代码恢复系统音量:
- (void)restoreSystemVolume { [self setSystemVolume:_originalSystemVolume]; }
这就是所有人。 希望有一天这个答案对你有很大的帮助。 🙂
感谢@Joris van Liempd iDeveloper。 从他的这个链接帮助我实现了这一点。