Detectar pressão do botão de volume do iPhone para cima?
-
12-12-2019 - |
Pergunta
Existe uma notificação que eu possa ouvir que me avisa quando o volume do iPhone está ligado acima?
eu sei sobre o AVSystemController_SystemVolumeDidChangeNotification
, mas é fundamental que a notificação só seja acionada quando o volume for aumentado, e não aumentado ou diminuído.
Em segundo lugar, como posso ocultar a visualização translúcida que aparece quando o botão de aumentar volume é pressionado, mostrando o volume do sistema? Câmera + implementou isso.
Solução
Não há uma maneira documentada de fazer isso, mas você pode usar esta solução alternativa.Registrar para AVSystemController_SystemVolumeDidChangeNotification
notificação e adicione um MPVolumeView
o que impedirá que a visualização do volume do sistema seja exibida.
MPVolumeView *volumeView = [[MPVolumeView alloc] initWithFrame:CGRectMake(-100, 0, 10, 0)];
[volumeView sizeToFit];
[self.view addSubview:volumeView];
E não se esqueça de iniciar uma sessão de áudio
AudioSessionInitialize(NULL, NULL, NULL, NULL);
AudioSessionSetActive(true);
Neste caso, o MPVolumeView
está oculto do usuário.
Para verificar se o volume para cima ou para baixo foi pressionado, basta pegar o volume do aplicativo atual
float volumeLevel = [[MPMusicPlayerController applicationMusicPlayer] volume];
e compare-o com o novo volume após o botão ser pressionado no retorno de chamada de notificação
Se você não quiser fazer isso sozinho, há uma aula presencial disponível no github
Outras dicas
Se quiser um evento você pode cadastrar um listener na propriedade "outputVolume":
- (void)viewWillAppear:(BOOL)animated {
AVAudioSession* audioSession = [AVAudioSession sharedInstance];
[audioSession setActive:YES error:nil];
[audioSession addObserver:self
forKeyPath:@"outputVolume"
options:0
context:nil];
}
-(void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([keyPath isEqual:@"outputVolume"]) {
NSLog(@"volume changed!");
}
}
Eu resolvi esse problema adicionando o próprio alvo/ação para o UISlider colocado dentro MPVolumeView
.Assim é possível capturar eventos de mudança de volume e determinar qual botão foi pressionado.Aqui está repositório do github com a implementação desta abordagem.Funciona bem com iOS 7 e superior, sem avisos de suspensão de uso e sem rejeição da Apple.
Para distinguir a ação do volume: EM VEZ DE (em observeValue guarda)
temp != 0.5
USAR apenas para aumentar o volume
temp > 0.5
e detectar apenas a diminuição do volume:
temp < 0.5
A solução abaixo será impressa se aumentar ou diminuir o volume for pressionado.
import AVFoundation
import MediaPlayer
override func viewDidLoad() {
super.viewDidLoad()
let volumeView = MPVolumeView(frame: CGRect.zero)
for subview in volumeView.subviews {
if let button = subview as? UIButton {
button.setImage(nil, for: .normal)
button.isEnabled = false
button.sizeToFit()
}
}
UIApplication.shared.windows.first?.addSubview(volumeView)
UIApplication.shared.windows.first?.sendSubview(toBack: volumeView)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
AVAudioSession.sharedInstance().addObserver(self, forKeyPath: "outputVolume", options: NSKeyValueObservingOptions.new, context: nil)
do { try AVAudioSession.sharedInstance().setActive(true) }
catch { debugPrint("\(error)") }
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
AVAudioSession.sharedInstance().removeObserver(self, forKeyPath: "outputVolume")
do { try AVAudioSession.sharedInstance().setActive(false) }
catch { debugPrint("\(error)") }
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
guard let key = keyPath else { return }
switch key {
case "outputVolume":
guard let dict = change, let temp = dict[NSKeyValueChangeKey.newKey] as? Float, temp != 0.5 else { return }
let systemSlider = MPVolumeView().subviews.first { (aView) -> Bool in
return NSStringFromClass(aView.classForCoder) == "MPVolumeSlider" ? true : false
} as? UISlider
systemSlider?.setValue(0.5, animated: false)
guard systemSlider != nil else { return }
debugPrint("Either volume button tapped.")
default:
break
}
}