有時在項目中須要監聽用戶是否按下了物理聲音鍵,而後來作某些操做,如:你自定義了一個照相功能,但願用戶按下聲音按鍵時也能進行拍照,蘋果自帶的照相機就有這種功能.app
監聽物理聲音鍵是否按下的方法有不少中,我在這裏只講兩種,也是我比較熟悉的ide
1、經過 NSNotificationCenter 觀察一個叫作 @「AVSystemController_SystemVolumeDidChangeNotification」 的通知,oop
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(volumeChanged:) name:@"AVSystemController_SystemVolumeDidChangeNotification" object:nil]; - (void)volumeChanged:(NSNotification *)notification { float volume = [[[notification userInfo] objectForKey:@"AVSystemController_AudioVolumeNotificationParameter"] floatValue]; NSLog(@"current volume = %f", volume); }
2、經過爲AudioSession添加一個監聽者來實現,測試
-(BOOL)addHardKeyListener{ OSStatus s = AudioSessionAddPropertyListener(kAudioSessionProperty_CurrentHardwareOutputVolume, hardKeyListener, "kAudioSessionProperty_CurrentHardwareOutputVolume"); return s==kAudioSessionNoError; } void hardKeyListener( void *inClientData, AudioSessionPropertyID inID, UInt32 inDataSize, const void *inData ){ if (inID != kAudioSessionProperty_CurrentHardwareOutputVolume) { return; } NSLog(@"%s",inClientData); }
對於上面這種方式,若是你直接這樣,那當你按下物理音量鍵時不會有任何的反應,你必須在調用它以前,手動初始化audioSessionspa
你能夠code
AudioSessionInitialize(NULL, kCFRunLoopDefaultMode, interruptionListenerCallback, "AudioSessionInitialize");server
或者直接blog
AudioSessionInitialize(NULL, NULL, NULL, NULL);rem
當你完成了上面的任何一種方式後,你就能夠很好的捕捉到音量鍵是否按下了,但此時你會發現,當你按下音量鍵時,系統自帶的,反映音量設置的view會it
出現,試想下,當你的用戶經過物理音量鍵操做你的程序,好比拍照,你還給人家顯示個系統的音量設置鍵,那用戶體驗可想而知了,
那怎麼解決呢?
那個系統自帶的音量設置view 其實就是個蘋果自定義的MPVolumeView,沒當音量鍵按下時,它都會出現,但若是當前顯示的正好有一個這樣的東西,那這個系統的音量設置view 就不會反客爲主,本身顯示出來了,而是顯示你本身定義的
呵呵,我就是不須要這個,那好辦,自定義一個,而後加到看不到的地方不就得了,
以下:
MPVolumeView *volumeView = [[MPVolumeView alloc]initWithFrame:CGRectMake(-100, -100, 100, 100)]; [self.view addSubview:volumeView];
但此時,你必須激活audioSession,否則得話它仍是會本身顯示得
加上代碼:
AudioSessionSetActive(true);
3、完成上面得東西后,你基本上能夠正常捕捉到音量鍵得按下,但有一點要注意:audioSession在你得程序進入後臺後會變爲不激活狀態,當你再次回到前臺後,你得程序得audioSession實際上是沒有激活得,此時,你按下音量鍵,那系統得那個音量設置view 就又出來了,因此你應該添加兩個系統通知,當程序進入後臺時
AudioSessionSetActive(false); 當程序進入前臺時 AudioSessionSetActive(true);
並且,若是捕捉音量鍵得按下只在某個畫面有效,那當該畫面再也不示但前顯示得畫面示應該移除捕捉動做
下面是一些測試用得代碼,沒有什麼邏輯關聯性
// // ViewController.m // AudioSessionDemo // // Created by PSH_Chen_Tao on 7/18/13. // Copyright (c) 2013 wolfman. All rights reserved. // #import "ViewController.h" #import <MediaPlayer/MediaPlayer.h> @interface ViewController () @end @implementation ViewController @synthesize imagePickerController; - (void)viewDidLoad { [super viewDidLoad]; // 得到當前的音量,由於按物理音量鍵,聲音會發生改變,咱們能夠在他每次按下音量鍵時都經過下面的初始音量值來還原它. float initVolume = [MPMusicPlayerController applicationMusicPlayer].volume; NSLog(@"%f ",initVolume); // Do any additional setup after loading the view, typically from a nib. AudioSessionInitialize(NULL, kCFRunLoopDefaultMode, interruptionListenerCallback, "AudioSessionInitialize"); //經過捕捉物理音量鍵按下時產生的通知來對其進行監聽 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(volumeChanged:) name:@"AVSystemController_SystemVolumeDidChangeNotification" object:nil]; [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(enterBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil]; [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(enterForground:) name:UIApplicationDidBecomeActiveNotification object:nil]; //避免按下音量鍵時,其系統自帶的音量設置畫面會出現 MPVolumeView *volumeView = [[MPVolumeView alloc]initWithFrame:CGRectMake(-100, -100, 100, 100)]; [self.view addSubview:volumeView]; } //進入後臺,釋放AudioSession -(void)enterBackground:(NSNotification *)n{ AudioSessionSetActive(false); } //進入前臺,激活AudioSession -(void)enterForground:(NSNotification *)n{ AudioSessionSetActive(true); } - (void)volumeChanged:(NSNotification *)notification { float volume = [[[notification userInfo] objectForKey:@"AVSystemController_AudioVolumeNotificationParameter"] floatValue]; NSLog(@"current volume = %f", volume); } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } void interruptionListenerCallback( void *inClientData, UInt32 inInterruptionState ){ if (inInterruptionState == kAudioSessionBeginInterruption) { NSLog(@"begin interruption"); } if (inInterruptionState == kAudioSessionEndInterruption) { NSLog(@"end interruption"); } NSLog(@"%s",inClientData); } -(BOOL)isMuted{ CFStringRef route; UInt32 routeSize = sizeof(route); OSStatus s = AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &routeSize, &route); if (s==kAudioSessionNoError) { if (route==NULL || CFStringGetLength(route)==0) { return YES; } } return NO; } -(BOOL)addMutedListener{ OSStatus s = AudioSessionAddPropertyListener(kAudioSessionProperty_AudioRouteChange, mutedListener, "kAudioSessionProperty_AudioRouteChange"); return s==kAudioSessionNoError; } void mutedListener( void *inClientData, AudioSessionPropertyID inID, UInt32 inDataSize, const void *inData ){ if (inID != kAudioSessionProperty_AudioRouteChange) { NSLog(@"inID != kAudioSessionProperty_AudioRouteChange %s",inClientData); return; } NSLog(@"%s",inClientData); } -(BOOL)addHardKeyListener{ OSStatus s = AudioSessionAddPropertyListener(kAudioSessionProperty_CurrentHardwareOutputVolume, hardKeyListener, "kAudioSessionProperty_CurrentHardwareOutputVolume"); return s==kAudioSessionNoError; } void hardKeyListener( void *inClientData, AudioSessionPropertyID inID, UInt32 inDataSize, const void *inData ){ if (inID != kAudioSessionProperty_CurrentHardwareOutputVolume) { return; } NSLog(@"%s",inClientData); } - (IBAction)addListener:(id)sender { [self addMutedListener]; [self addHardKeyListener]; } - (IBAction)removeListener:(id)sender { AudioSessionRemovePropertyListenerWithUserData(kAudioSessionProperty_CurrentHardwareOutputVolume, hardKeyListener, "kAudioSessionProperty_CurrentHardwareOutputVolume"); } -(void)viewWillAppear:(BOOL)animated{ [super viewWillAppear:animated]; // AudioSessionInitialize(NULL, NULL, NULL, NULL); AudioSessionSetActive(true); } -(void)viewWillDisappear:(BOOL)animated{ [super viewWillDisappear:animated]; AudioSessionSetActive(false); } @end