聊聊iOS開發中耳機的那點事(監聽耳機拔插、耳機線控)-b


如果說一個項目出現的最重大的事故,那無疑就是開發人員使用了不可控的元素.

 

前言


iOS開發當中有關於視音頻播放的開發不在少數,用戶時常會使用到一種輸出設備,那就是"耳機",這一篇博客寫的就是關於耳機的一些開發相關的技術點.

檢測耳機是否插入


看到上面的標題的時候一定要注意,這里說的是"檢測耳機是否插入",這里只是一次性的檢測,不是實時監控耳機的拔插,但是有一些時候,下面的這個方法已經足夠滿足我們的開發需求了.
首先,我們需要導入AVFoundation.framework這個框架如下圖.

導入AVFoundation.framework框架

然后導入頭文件,實現下面的方法
#import <AVFoundation/AVFoundation.h>  //導入頭文件
- (BOOL)isHeadsetPluggedIn {       
    AVAudioSessionRouteDescription* route = [[AVAudioSession sharedInstance] currentRoute];       
    for (AVAudioSessionPortDescription* desc in [route outputs]) {           
        if ([[desc portType] isEqualToString:AVAudioSessionPortHeadphones])               
            return YES;       
    }       
    return NO;   
}
 

監聽耳機的拔插 (iOS6.0的實現)


其實這幾天一直在看網上的相關的資料,發現監聽耳機拔插大多數是一些iOS6.0左右的老方法,我們就先拋磚引玉一下,先看看iOS6.0是如何監聽耳機拔插事件.
首先,我們需要導入AVFoundation.framework這個框架如下圖.

導入AVFoundation.framework框架

iOS6.0的監聽耳機拔插主要是對AVAudioSession單例對象中的AudioSessionAddPropertyListener 這個 block函數的實現完成的,這個函數在耳機拔插的時候調用才會調用.這里的監聽耳機拔插事件我直接寫在了AppDelegate中- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions,我們看一下具體的代碼實現.
#import "AppDelegate.h"
#import <AVFoundation/AVFoundation.h>//導入頭文件
@interface AppDelegate ()<AVAudioSessionDelegate>

@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {      
    [[AVAudioSession sharedInstance] setDelegate:self];//初始化單例設置代理      
    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];//設置AVAudioSession單例對象的類型      
    AudioSessionAddPropertyListener(kAudioSessionProperty_AudioRouteChange,audioRouteChangeListenerCallback, (__bridge void *)(self));//調用block函數      
    return YES; 
}//對block函數其中的方法進行實現
void audioRouteChangeListenerCallback (void *inUserData, AudioSessionPropertyID inPropertyID, UInt32 inPropertyValueSize,const void *inPropertyValue ) {    // ensure that this callback was invoked for a route change       if (inPropertyID != kAudioSessionProperty_AudioRouteChange) return;      {            // Determines the reason for the route change, to ensure that it is not              //      because of a category change.              CFDictionaryRef routeChangeDictionary = (CFDictionaryRef)inPropertyValue;        CFNumberRef routeChangeReasonRef = (CFNumberRef)CFDictionaryGetValue (routeChangeDictionary, CFSTR (kAudioSession_AudioRouteChangeKey_Reason) );              SInt32 routeChangeReason;            CFNumberGetValue (routeChangeReasonRef, kCFNumberSInt32Type, &routeChangeReason);        if (routeChangeReason == kAudioSessionRouteChangeReason_OldDeviceUnavailable) {            //Handle Headset Unplugged                  NSLog(@"沒有耳機!");           } else if (routeChangeReason == kAudioSessionRouteChangeReason_NewDeviceAvailable) {            //Handle Headset plugged in                  NSLog(@"有耳機!");           }      }  }
 

監聽耳機的拔插 (iOS6.0之后的實現)


其實,如果不是一個有警告情結的程序猿,上面的監聽耳機拔插實現已經完全能滿足工作需求,但是對於我這么一個有警告情結的程序猿,心中對上面的程序運行過程出現的警告十分的反感,在上面的AVAudioSession很多方法被棄用之后,我們需要使用通知來實現監聽耳機的拔插.所以就出現了下面的方法.
下面的方法我為了方便,就直接下載Demo的ViewController中,和上面一樣,我們需要導入AVFoundation.framework這個框架.然后我們在ViewController導入頭文件.然后我們需要監聽的通知名稱如下.
AVAudioSessionRouteChangeNotification  //需要監聽的通知名稱
具體的代碼實現,如下.
#import "ViewController.h"
#import <AVFoundation/AVFoundation.h>
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {     
    [super viewDidLoad];      
    [[AVAudioSession sharedInstance] setActive:YES error:nil];//創建單例對象並且使其設置為活躍狀態.      
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(audioRouteChangeListenerCallback:)   name:AVAudioSessionRouteChangeNotification object:nil];//設置通知
}//通知方法的實現 - (void)audioRouteChangeListenerCallback:(NSNotification*)notification {            NSDictionary *interuptionDict = notification.userInfo;            NSInteger routeChangeReason = [[interuptionDict valueForKey:AVAudioSessionRouteChangeReasonKey] integerValue];            switch (routeChangeReason) {                    case AVAudioSessionRouteChangeReasonNewDeviceAvailable:                            NSLog(@"AVAudioSessionRouteChangeReasonNewDeviceAvailable");                            tipWithMessage(@"耳機插入");                            break;                    case AVAudioSessionRouteChangeReasonOldDeviceUnavailable:                            NSLog(@"AVAudioSessionRouteChangeReasonOldDeviceUnavailable");                 tipWithMessage(@"耳機拔出,停止播放操作");                            break;                    case AVAudioSessionRouteChangeReasonCategoryChange:            // called at start - also when other audio wants to play                            tipWithMessage(@"AVAudioSessionRouteChangeReasonCategoryChange");                            break;         } }//不管何時,只要有通知中心的出現,在dealloc的方法中都要移除所有觀察者. -(void)dealloc{          [[NSNotificationCenter defaultCenter] removeObserver:self];   } //自定提醒窗口 NS_INLINE void tipWithMessage(NSString *message){        dispatch_async(dispatch_get_main_queue(), ^{                UIAlertView *alerView = [[UIAlertView alloc] initWithTitle:@"提示" message:message delegate:nil cancelButtonTitle:nil otherButtonTitles:nil, nil];                  [alerView show];                  [alerView performSelector:@selector(dismissWithClickedButtonIndex:animated:) withObject:@[@0, @1] afterDelay:0.9];         });   }
 

監聽耳機的拔插的注意事項(必看部分)


  • 1.開發人員測試監聽耳機的拔插的代碼的時候,要使用真機測試.模擬器是沒有耳機插孔的,除非你給電腦鑿一個孔.😁
  • 2.不管是使用iOS6.0之前的方法還是之后的方法,有個先決條件,那就是AVAudioSession這個類的單例對象必須在一開始初始化,否則不管是block隱形函數還是通知方法都不能實現.
  • 3.這個注意事項是個老生常談的問題了,那就是一旦出現了通知中心,那么在當前控制器的dealloc方法中一定要移除通知中心的所有觀察者.

耳機線控的按鍵的監控


耳機的線控

眾所周知,iPhone耳機都是有線控部分的,那么我們該如何實現呢?,其實,實現的核心就是UIResponder類中的- (void)remoteControlReceivedWithEvent:(UIEvent *)event方法,這個方法有以下的兩個作用.我們需要用到的就是第一個作用.
  • 接收到一個遠程控制事件。比如耳機控制。

  • 允許傳遞遠程控制事件,必須調用UIApplication的beginReceivingRemoteControlEvents方法;關閉遠程控制,調用endReceivingRemoteControlEvents。

和上面一樣,我們依然是需要導入AVFoundation.framework這個框架.然后我們在ViewController導入頭文件.
當然了,實現耳機線控的按鍵的監控是有以下三個前提的.
  • 1.啟用遠程事件接收(使用[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];方法)。

  • 2.對於UI控件同樣要求必須是第一響應者(對於視圖控制器UIViewController或者應用程序UIApplication對象監聽無此要求)。

  • 3.應用程序必須是當前音頻的控制者,也就是在iOS 7中通知欄中當前音頻播放程序必須是我們自己開發程序。

具體代碼實現,如下.
-(BOOL)canBecomeFirstResponder{    
    return YES; 
}
//received remote event
-(void)remoteControlReceivedWithEvent:(UIEvent *)event{    
    NSLog(@"event tyipe:::%ld   subtype:::%ld",(long)event.type,(long)event.subtype);    //type==2  subtype==單擊暫停鍵:103,雙擊暫停鍵104     
    if (event.type == UIEventTypeRemoteControl) {        
        switch (event.subtype) {            
            case UIEventSubtypeRemoteControlPlay:{                
                NSLog(@"play---------");             
                }break;            
            case UIEventSubtypeRemoteControlPause:{                
                NSLog(@"Pause---------");             
                }break;            
            case UIEventSubtypeRemoteControlStop:{                
                NSLog(@"Stop---------");             
                }break;            
            case UIEventSubtypeRemoteControlTogglePlayPause:{                
                //單擊暫停鍵:103                 
                NSLog(@"單擊暫停鍵:103");             
                }break;            
            case UIEventSubtypeRemoteControlNextTrack:{                //雙擊暫停鍵:104                 
                NSLog(@"雙擊暫停鍵:104");             
                }break;            
            case UIEventSubtypeRemoteControlPreviousTrack:{                
                NSLog(@"三擊暫停鍵:105");             
                }break;            
            case UIEventSubtypeRemoteControlBeginSeekingForward:{                
                NSLog(@"單擊,再按下不放:108");             
                }break;            

            case UIEventSubtypeRemoteControlEndSeekingForward:{                
                NSLog(@"單擊,再按下不放,松開時:109");                 }break;            
            default:                
                break;         
        }     
    } 
}
 

 

---> 麻辣味Demo:https://yun.baidu.com/share/link?shareid=2650043582&uk=4079807053

文/神經騷棟(簡書作者)
原文鏈接:http://www.jianshu.com/p/87f3f2024038


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM