uniapp 播放声音你一定要看的

1,299 阅读3分钟

介绍

仓库人员使用PDA扫码时是比较关注提示音播放的,但是陆陆续续出现了一些问题,对用户影响较大

image.png

PDA使用的是uniapp框架打包成APP实现

声音播放使用的是uni.createInnerAudioContext()来创建使用

排查难点

  1. 需要联接PDA调试,手机和PC上复现不了
  2. uniapp的调试模式比较简陋,只能console
  3. 在极端使用情况下才能触发

问题一 扫码多次后APP严重卡顿

结论:同一个innerAudioContext实例不能多次执行播放

重点对扫码操作进行了排查,连续使用激光扫码超20+后,出现APP整体卡顿,无法操作

排查扫码逻辑后发现是有一些代码可优化,但扫码优化后卡顿依旧

每次扫码后都会播放成功/失败的提示音,关闭提示音播放,使用明显流畅了

官方也未做出注明为什么播放声音会导致卡顿

最终捣鼓发现,原因是不能使用同一个innerAudioContext实例来多次播放

本意是使用单例模式减少多次创建的开销

问题二 偶尔出现不播放

结论:自动播放使用autoplay = true,不要使用play()

只有出入库扫码后出现,且无法每次必现,增加了调试难度

原代码写法是先创建实例

const audioContext = uni.createInnerAudioContext();

然后赋值文件源,type是文件名

audioContext.src = `/static/voice/${type}.mp3`;

最后播放

audioContext.play();

正常情况都能播放,10次有1-2次没声音

加上onError事件后没声音也不触发error,难以定位

audioContext.onError((e) => {  
   console.log('onError', e);  
});

最终捣鼓发现,需要在赋值文件src前,使用autoplay = true,而不能赋值后直接调用play()

注:如果非要使用play(),可以在onCanplay事件回调里执行播放

audioContext.autoplay = true;  
audioContext.src = `/static/voice/${type}.mp3`;

这里的原因比较明显,音源赋值后可能并未加载完成,此时不能直接播放,但是不报错增加了排查的难度

问题三 连续多次播放,后续整个APP都没声音了

结论:实例数量超过了上限,需要销毁实例后再创建

在快速录入零件时,播放多了后概率出现APP声音没了,重启应用后才又有声音

这个问题有一部分PDA复现不了,不巧本人拿的就是这种PDA,耽误了一些时间在测试上

在加上onError捕获后可以检测到异常,原因是创建了过多的实例不能再创建了

于是在播放结束时销毁实例

audioContext.onEnded(() => {  
   audioContext.destroy();  
});

试了试发现不行,于是查到不少同样问题的帖子,需要在onPause里调用销毁实例

试了下貌似可以一直播放了,但发现一个问题:在快速播放时,第2次播放声音会与第一次声音重叠,按理来说,同一时间应该只有一个声音在播放

这里尝试在创建实例前销毁上一次实例

audioContext?.destroy();  
audioContext = uni.createInnerAudioContext();

这样两次快速播放过程就是onPlayonStoponPlayonEnded

最终代码

let audioContext;

/**
 * 播放音频
 * @param {string} type warn | right
 */
const playVoice = (type) => {
    return new Promise((resolve) => {
        audioContext?.destroy();
        audioContext = uni.createInnerAudioContext();
        audioContext.onEnded(() => {
            // 播放结束
            resolve();
        });
        audioContext.onError((e) => {
            console.log('play voice error', e);
        });

        audioContext.autoplay = true;
        audioContext.src = `/static/voice/${type}.mp3`;
    });
};

export default playVoice;