iOS音量控制界面控制Tips

iOS音量控制界面控制Tips

AVFoundation 框架提供了播放音频和视频的工具,使用 AVFoundation 基本能满足我们的大部分的播放需求。

在一些需求开发中,通常有一些骚操作需要自定义或者隐藏音量控制界面

MPVolumeView

先看看官方的解释

A slider control used to set the system audio output volume, and a button for choosing the audio output route.

Use a volume view to present the user with a slider control for setting the system audio output volume, and a button for choosing the audio output route. When first displayed, the slider’s position reflects the current system audio output volume. As the user drags the slider, the changes update the volume view. If the user presses the device volume buttons while sound is playing, the slider moves to reflect the new volume.

MPVolumeView是系统级别的音量控制View,但是他并不是一个单例全局获得,不是通过类似 UIApplication 来获得,他只是简单就能获得

1
_systemVolumeView = [[MPVolumeView alloc]initWithFrame:CGRectZero];

当然不是说只是把他设置Frame 为0就可以简单隐藏,也不能通过设置 _systemVolumeView.hidden = YES 隐藏

通常做法就是将其添加到屏幕外位置达到隐藏效果。

此时需要注意的是,如果你把系统的音量控制View隐藏了,切回后台调节音量也是不会显示的,你要_systemVolueView移除,才会重新出现.

回到项目需求上

一切都是需求驱动技术,先说下最近的需求

需求要求是自定义相机里面,通过按下音量键做到拍照功能且音量不变化

先说下思路:

  1. 首先进到功能页面需要隐藏MPVolumeView
  2. 监听系统音量变化通知或者KVO,总之就是监听音量变化,获得前后音量大小
  3. 改动音量,保持不变
  4. 调用拍照方法
  5. 切换到后台时候重新显示系统音量,切换回来App重新隐藏

确定了思路之后开始设计结构,由于之前写了一篇技术博文,也是关于这方面控制的,本以为只是简单的操作下就好,怎么知道也是有很多坑.博文: iOS7 以上监听音量键Tips

本来只是平移移植过来,以为就能用了,怎么知道出现了切换到后台,按了下音量切换回App还是出现音量View.

由于原来那套部署在另外App上,而且也是几年前写的,也可能每个App业务逻辑上不同,也会导致这个问题。

所以需要重新设计一套成熟一点的框架与架构

MPVolumeObserver

这次搜索过一些博客文章,文章方法基本都是不行的。直到参考了一个github库 VolumeBar,也大概了解到为什么原来那套方案切换到后台调整音量后,切换回App就会显示.

首先原来那套方案,使用单例全局管理了一个音量控制类.初始化时候将MPVoluemeView 创建了就加到当前屏幕window 看不见的地方, 暂停时候也没有去除。后来我也试过手动在stopObserver停止监听中,将MPVolumeView移除,后来就出现上面所说问题,回到App重新添加,即使添加到看不见地方也是会出现

先说下这个架构,MPVolumeObserver是个全局单例,监听系统与用户事件,如切换到后台,切换回前台,音量变化.

MPVolueObserver中包括两个小类 JNEMPVolumeObserverWindow(用于承载MPVolumeView的伪造window,不参加用户操作反馈) 、JNEMPVolumeManager(监听系统音量变化)

MPVolumeObserverWindow

参考了这个库,得出结论是,开始监听时候,需要创建一个window之类的承载体.(这个也是可能原来那套方案问题,因为原来是添加到当前window最顶层,删除添加都是基于这层的。可能系统只是支持一次添加,删除后再添加就能隐藏了(自己猜测且实践过).所以每次创建的这个新的 window 载体设置了大小,添加这个系统MPVoluemeview,且这个window可以隐藏

1
2
3
4
5
6
7
8
//MPVolumeObserver
_obWindow = [[JNEMPVolumeObserverWindow alloc]initWithViewController:vc];

//JNEMPVolumeObserverWindow
_systemVolumeView = [[MPVolumeView alloc]initWithFrame:CGRectZero];
[self addSubview:_systemVolumeView];
//blablabla

MPVolumeManager

这个是监听系统音量的类,之前方案是监听系统通知 SystemVolumeDidChange , 但是研究过这个,因为通知名是私有的,苹果爸爸到时改了就没法用了。所以现在方案是使用KVO 监听AVAudioSessionoutputVolume 来实现音量监听

此时再说明下AVAudioSession

可以看到AVAudioSession就是用来管理多个APP对音频硬件设备(麦克风,扬声器)的资源使用。

举例一下AVAudioSession可以做这些事情

  • 设置自己的APP是否和其他APP音频同时存在,还是中断其他APP声音
  • 在手机调到静音模式下,自己的APP音频是否可以播放出声音
  • 电话或者其他APP中断自己APP的音频的事件处理
  • 指定音频输入和输出的设备(比如是听筒输出声音,还是扬声器输出声音)
  • 是否支持录音,录音同时是否支持音频播放

MPVolumeManager中每次监听需要激活一下AVAudioSession

1
2
//激活AVAudioSession
[session setActive:YES error:nil];

即可开始监听系统音量

最后的最后,献上这个音量库: MPVolumeObserver

Reference

1.iOS-音频-AVAudioSession

iOS音量控制界面控制Tips

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

Author

Sylar

Posted on

2019-04-28

Updated on

2021-11-14

Licensed under

Comments