如何在不监听事件的情况下获取React Native可用音频设备列表?
直接获取可用音频设备列表的实现方案
方案1:扩展原生模块,新增同步获取方法
react-native-incall-manager本身的JS API没有直接提供主动获取设备列表的接口,但可以通过扩展原生模块来实现:
Android端实现
修改InCallManagerModule.java,添加一个获取设备列表的方法:
@ReactMethod public void getAvailableAudioDevices(Promise promise) { AudioManager audioManager = (AudioManager) getReactApplicationContext().getSystemService(Context.AUDIO_SERVICE); List<String> devices = new ArrayList<>(); // 检查蓝牙设备 if (audioManager.isBluetoothScoAvailableOffCall()) { devices.add("bluetooth"); } // 检查扬声器 if (audioManager.isSpeakerphoneOn()) { devices.add("speaker"); } // 检查听筒 devices.add("earpiece"); // 检查有线耳机 if (audioManager.isWiredHeadsetOn()) { devices.add("headphones"); } promise.resolve(devices); }
JS层调用方式:
import InCallManager from 'react-native-incall-manager'; async function fetchAudioDevices() { try { const devices = await InCallManager.getAvailableAudioDevices(); return devices; } catch (err) { console.error('获取音频设备失败:', err); return []; } }
iOS端实现
修改InCallManager.m,添加对应方法:
#import <AVFoundation/AVFoundation.h> RCT_EXPORT_METHOD(getAvailableAudioDevices:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { AVAudioSession *session = [AVAudioSession sharedInstance]; NSMutableArray *devices = [NSMutableArray array]; for (AVAudioSessionPortDescription *port in session.availableInputs) { if ([port.portType isEqualToString:AVAudioSessionPortBluetoothA2DP] || [port.portType isEqualToString:AVAudioSessionPortBluetoothHFP]) { [devices addObject:@"bluetooth"]; } else if ([port.portType isEqualToString:AVAudioSessionPortBuiltInSpeaker]) { [devices addObject:@"speaker"]; } else if ([port.portType isEqualToString:AVAudioSessionPortHeadphones]) { [devices addObject:@"headphones"]; } else if ([port.portType isEqualToString:AVAudioSessionPortBuiltInMic]) { [devices addObject:@"earpiece"]; } } resolve(devices); }
JS层调用和Android端一致。
方案2:缓存事件返回的设备列表(无需修改原生)
如果不想动原生代码,可以在应用初始化时就监听onAudioDeviceChanged事件,把返回的设备列表缓存到全局变量,之后直接读取缓存即可:
import InCallManager from 'react-native-incall-manager'; // 全局缓存设备列表 let cachedAudioDevices = []; // 初始化时监听事件并更新缓存 InCallManager.addEventListener('onAudioDeviceChanged', (data) => { cachedAudioDevices = data.availableAudioDeviceList; }); // 主动获取设备列表的方法 function getAvailableAudioDevices() { // 首次调用如果缓存为空,临时切换音频路由触发事件更新缓存 if (cachedAudioDevices.length === 0) { const currentRoute = InCallManager.getAudioRoute(); InCallManager.setAudioRoute('speaker'); setTimeout(() => { InCallManager.setAudioRoute(currentRoute); }, 100); } return cachedAudioDevices; }
注意:首次调用可能需要等待事件触发,建议在应用启动后提前初始化监听。
结合React-Native-WebRTC的补充方案
WebRTC的mediaDevices也能获取设备列表,可作为辅助手段:
import { mediaDevices } from 'react-native-webrtc'; async function getWebRTCAudioDevices() { const allDevices = await mediaDevices.enumerateDevices(); const audioDevices = allDevices.filter(device => device.kind.includes('audio')); // 映射成和incall-manager一致的命名格式 return audioDevices.map(device => { if (device.label.includes('Bluetooth')) return 'bluetooth'; if (device.label.includes('Speaker')) return 'speaker'; if (device.label.includes('Headphones')) return 'headphones'; return 'earpiece'; }); }
这种方式的设备标签可能因机型差异有所不同,需要做兼容处理。
内容的提问来源于stack exchange,提问作者vuminh
相关产品推荐
相关产品推荐

