想在应用中监听有线耳机 / 蓝牙耳机的插拔,看到文档有 AudioRoutingManager 的 on('deviceChange', ...) 接口,就按示例写了代码。但实际插拔耳机时,控制台没有任何日志,回调好像从来没触发过。
import audio from '@ohos.multimedia.audio';
let audioRoutingManager: audio.AudioRoutingManager;
async function initRouting() {
audioRoutingManager = await audio.getAudioManager().getRoutingManager();
console.info('audioRoutingManager create success');
audioRoutingManager.on('deviceChange',
audio.DeviceFlag.ALL_DEVICES_FLAG,
(deviceChanged) => {
console.info('on device change type:' + deviceChanged.type);
});
}
在 EntryAbility 的 onWindowStageCreate 里调用了 initRouting()。应用前台运行时插上耳机,没有日志输出,也没有报错。
AudioRoutingManager 的典型用法大致是正确的,但要注意几个容易踩坑的点:
-
确保
audioRoutingManager变量在整个应用生命周期内是“活着”的
如果把audioRoutingManager定义在函数内部,函数执行完就会被 GC,事件回调自然不会触发。你已经把它提到了模块级变量,这是对的,要确保初始化后不要被覆盖。 -
确认实际调用了初始化方法并等待 Promise 完成
建议在初始化时加上await和错误打印,避免 Promise 被悄悄拒绝:async function initRouting() { try { audioRoutingManager = await audio.getAudioManager().getRoutingManager(); console.info('audioRoutingManager create success'); audioRoutingManager.on( 'deviceChange', audio.DeviceFlag.ALL_DEVICES_FLAG, (deviceChanged) => { console.info('on device change, type: ' + deviceChanged.type); console.info('descriptor length: ' + deviceChanged.deviceDescriptors.length); } ); } catch (err) { console.error('initRouting error: ' + JSON.stringify(err)); } } -
保证回调注册时应用处于前台且没有立刻销毁 Ability
如果你在某个页面生命周期很短的 Ability 里注册监听,然后页面立刻退出,回调也很难触发。推荐在主入口EntryAbility或应用级单例里初始化路由监听。 -
确认使用的是支持该能力的版本和设备
官方文档中AudioRoutingManager要求SystemCapability.Multimedia.Audio.Core,部分低版本模拟器不支持耳机插拔事件,你已经在真机上测试,这是正确姿势。Gitee+1 -
模块选择问题
当前公开文档里AudioRoutingManager示例确实是基于@ohos.multimedia.audio模块的 JS/TS API,示例代码与你写的一致。如果你在同一工程里又引入了@kit.AudioKit,建议避免类型混用,routing 相关统一使用一个模块。
综合以上几点,一般做法是:
-
在应用启动时调用一次
initRouting(); -
确保
audioRoutingManager是模块级单例; -
真机上插拔耳机时,就可以在日志里看到
deviceChange回调了。
如果依然没反应,可以用 getDevices(DeviceFlag.ALL_DEVICES_FLAG) 打印一次设备列表,看当前设备枚举是否正常,进一步定位是事件问题还是底层设备枚举问题。