Cleanest way of capturing volume up/down button press on iOS 8

回眸只為那壹抹淺笑 提交于 2019-11-26 17:44:25

For Swift you can use next code in your viewController class:

let volumeView = MPVolumeView(frame: CGRectMake(-CGFloat.max, 0.0, 0.0, 0.0))
self.view.addSubview(volumeView)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(volumeChanged(_:)), name: "AVSystemController_SystemVolumeDidChangeNotification", object: nil)

Then add this function

func volumeChanged(notification: NSNotification) {

     if let userInfo = notification.userInfo {
        if let volumeChangeType = userInfo["AVSystemController_AudioVolumeChangeReasonNotificationParameter"] as? String {
            if volumeChangeType == "ExplicitVolumeChange" {
                // your code goes here
            }
        }
    }
}

This code detect the explicit volume change action by the user, as if you didn't check of the explicit action, this function will be automatically called periodically.

This code don't prevent the system volume change

First add AVFoundation and MediaPlayer Framework and then you can use below code to detect up/down button press,

-(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"]) {        
      float volumeLevel = [[MPMusicPlayerController applicationMusicPlayer] volume];
      NSLog(@"volume changed! %f",volumeLevel);
  }
}

for swift 3: (remember to add: import MediaPlayer.. )

    override func viewDidLoad() {
        super.viewDidLoad()

        let volumeView = MPVolumeView(frame: CGRect(x: 0, y: 40, width: 300, height: 30))
        self.view.addSubview(volumeView)
//      volumeView.backgroundColor = UIColor.red
        NotificationCenter.default.addObserver(self, selector: #selector(volumeChanged(notification:)),
                                               name: NSNotification.Name(rawValue: "AVSystemController_SystemVolumeDidChangeNotification"),
                                               object: nil)
    }


    func volumeChanged(notification: NSNotification) {

        if let userInfo = notification.userInfo {
            if let volumeChangeType = userInfo["AVSystemController_AudioVolumeChangeReasonNotificationParameter"] as? String {
                if volumeChangeType == "ExplicitVolumeChange" {
                    // your code goes here
                }
            }
        }
    }

....

Ah ok, see the Audio Session Services References for more information. You need to start an audio session with AudioSessionInitialize and then make it active with AudioSessionSetActive, listen for changes in the volume with AudioSessionAddPropertyListener and pass a callback that has type AudioSessionPropertyListener.

This web site has a good write up: http://fredandrandall.com/blog/2011/11/18/taking-control-of-the-volume-buttons-on-ios-like-camera/

Objective-C version (using notifications):

#import <MediaPlayer/MPVolumeView.h>
#import <AVFoundation/AVFoundation.h>

@interface ViewController () {
    UISlider *volumeViewSlider;
}

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self startTrackingVolumeChanges];
}

- (void)dealloc
{
    [self stopTrackingVolumeChanges];
}

#pragma mark - Start Tracking Volume Changes

- (void)startTrackingVolumeChanges
{
    [self setupVolumeViewSlider];
    [self addObserver];
    [self activateAudioSession];
}

- (void)setupVolumeViewSlider
{
    MPVolumeView *volumeView = [[MPVolumeView alloc] init];
    for (UIView *view in [volumeView subviews]) {
        if ([view.class.description isEqualToString:@"MPVolumeSlider"]) {
            volumeViewSlider = (UISlider *)view;
            break;
        }
    }
}

- (void)addObserver
{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(volumeChanged:) name:@"AVSystemController_SystemVolumeDidChangeNotification" object:nil];
}

- (void)activateAudioSession
{
    AVAudioSession *audioSession = [AVAudioSession sharedInstance];
    [audioSession setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionMixWithOthers error:nil];
    NSError *error;
    BOOL success = [audioSession setActive:YES error:&error];
    if (!success) {
        NSLog(@"Error activating audiosession: %@", error);
    }
}

#pragma mark - Observing Volume Changes

- (void)volumeChanged:(NSNotification *)notification
{
    NSString *volumeChangeType = notification.userInfo[@"AVSystemController_AudioVolumeChangeReasonNotificationParameter"];
    if ([volumeChangeType isEqualToString:@"ExplicitVolumeChange"]) {
        float volume = volumeViewSlider.value;
        NSLog(@"volume = %f", volume);
    }
}

#pragma mark - Stop Tracking Volume Changes

- (void)stopTrackingVolumeChanges
{
    [self removeObserver];
    [self deactivateAudioSession];
    volumeViewSlider = nil;
}

- (void)removeObserver
{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"AVSystemController_SystemVolumeDidChangeNotification" object:nil];
}

- (void)deactivateAudioSession
{
    dispatch_async(dispatch_get_main_queue(), ^{
        NSError *error;
        BOOL success = [[AVAudioSession sharedInstance] setActive:NO error:&error];
        if (!success) {
            NSLog(@"Error deactivating audiosession: %@", error);
        }
    });
}

@end
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!