uniapp小程序语音播报功能

小程序语音播报

背景:项目中有一个功能是小程序扫码之后进行语音播报,使用uni.createInnerAudioContext方法,并不是一帆风顺的,所以记录一下。

需要注意的点

  • 全局使用一个音频实例(uni 官方建议这种方法,因为频繁切换 src,可能会出现-99 的错误)
  • 语音播放过程中,调用uni.scanCode会中断语音
  • 据测试,ios直接播放,会出现延迟播放的情况,项目里面使用uni.downloadFile将资源下载下来,再播放可以有效缓解该问题
  • ios直接进行播放,可能是由于音频资源没准备好,可能会直接进入到onError,这时根据错误码重新调用播放即可。 碰到的两种错误信息如下:
  1. {"errMsg": "operateAudio:fail jsapi has no permission, event=operateAudio, runningState=background, permissionMsg=permission got, detail=jsapi has no permission, appId=wxd161895220febc6f", "errCode": -1}

  2. {"errMsg": "operateAudio:fail audioInstance is not set", "errCode": -1}

代码示例

ts 复制代码
import { onUnload } from "@dcloudio/uni-app";
let innerAudioContext: any = null;
// 销毁音频
const destroyAudio = () => {
  if (innerAudioContext) {
    innerAudioContext.stop();
    innerAudioContext.destroy();
    innerAudioContext = null;
  }
};
// 创建音频
const createAudio = (audioSrc: string) => {
  destroyAudio(); // 每次创建将上一个实例销毁
  innerAudioContext = uni.createInnerAudioContext();
  innerAudioContext.src = audioSrc;
  // 播放事件
  innerAudioContext.onPlay(() => {
    console.log("play audio");
  });
  // 播放结束事件
  innerAudioContext.onEnded(() => {
    console.log("ended audio");
  });
  // 播放错误事件
  innerAudioContext.onError((error: any) => {
    console.log("play audio error", error);
    // 兼容ios(估计是官方bug),可能是ios资源没准备好时,播放会发生错误返回errCode为-1,这时需要重新播放,直至播放成功
    if (error.errCode === -1) {
      createAudio(audioSrc);
    } else {
      // 比如文件不存在等情况,会进入到这个提示
      uni.showToast({
        title: "播放失败:" + error.errMsg,
        icon: "none",
      });
    }
  });
  innerAudioContext.play();
};
const downloadAudio = (fileName: string) => {
  if (!fileName) {
    return;
  }
  // 扫码失败时接口返回一个音频文件名,通过文件名拼接成完整的音频地址
  const audioUrl = "https://xxx.com/static/" + fileName;
  // 先将资源下载下来,在ios下播放速度会更快(经本人测试,不下载,直接播放,ios机型会有明显的延迟播放行为)
  uni.downloadFile({
    url: audioUrl,
    success: ({ tempFilePath }) => {
      createAudio(tempFilePath);
    },
  });
};
const onScan = () => {
    uni.scanCode({
        success(res) {
            // 扫码结果
            scanCheck(res.result);
        },
    });
};
const scanCheck = (code: string) => {
  // 发送扫码请求
  scanRequest(code)
    .then(() => {
      // 扫码成功之后,每隔1s进行一次扫码
      setTimeout(() => onScan(), 1000);
      uni.showToast({
        title:"扫码成功",
        icon:'none',
        mask:true
      }
      );
    })
    .catch((res) => {
      // 扫码失败之后,利用接口返回的文件名创建语音实例,播报音频
      downloadAudio(res.fileName);
      uni.showToast({
        title:res.msg|| "扫码失败",
        icon:'none',
        mask:true,
        duration:2000
      }
    });
};
onUnload(() => {
  // 页面卸载时销毁音频
  destroyAudio();
});
相关推荐
烟囱土著几秒前
捣鼓30天,我写了一个数学加减练习小程序
学习·算法·微信小程序·小程序
拾忆,想起几秒前
Dubbo灰度发布完全指南:从精准引流到全链路灰度
前端·微服务·架构·dubbo·safari
liudongyang1233 分钟前
EasyExcel使用模版填充的方式,导致单元格边框消失
前端·html
2503_928411562 小时前
12.4 axios的二次封装-深拷贝
前端·javascript·vue.js
你真的可爱呀5 小时前
uniapp+vue3项目中的常见报错情况以及解决方法
前端·vue.js·uni-app
差点GDP9 小时前
模拟请求测试 Fake Rest API Test
前端·网络·json
酒尘&10 小时前
Hook学习-上篇
前端·学习·react.js·前端框架·react
houyhea10 小时前
从香港竹脚手架到前端脚手架:那些"借来"的发展智慧与安全警示
前端
哈哈~haha10 小时前
Step 14: Custom CSS and Theme Colors 自定义CSS类
前端·css·ui5
Ndmzi11 小时前
Matlab编程技巧:自定义Simulink菜单(理解补充)
前端·javascript·python