安卓机调用 audio.play()时 报错:API can only be initiated by a user gesture
需求与bug解决
做 H5开发的一个需求:页面内有一个按钮点击可以播放语音,产品提供的素材是多段语音,并配有对应文字;
bug1: 切换到后台时,语音还在播放,
解决方法:增加 visibilitychange 监听事件,用 document.hidden 判断是否处于后台。
mounted() {this.audioTemp = new Audio(AthenaData.audioList[0].voice);// 切到后台停止语音document.addEventListener('visibilitychange', () => {if (document.hidden) {this.musicDisabled = false; // 按钮状态this.audioTemp.pause();}});},
bug2: API can only be initiated by a user gesture
原因:部分安卓机要求调用 audio.play() 这个接口必须要用户手势触发,也就是必须是真实的用户操场类似 click之类的事件去触发才行,用js主动去触发dom的click的话也是无效的!
解决方案有二:1. 安卓端上有对应的 api 设置可以取消这个限制,但一定会有合规方面的风险(法务检测那边可能无法通过)2.将多段语音合成一段。
功能实现
template:
// 播放按钮 <divv-image.normal="musicDisabled ? AthenaData.horn1 : AthenaData.horn2"class="horn1"@click="onBgmMusicClick"/>// 滚动文字<divref="box"class="tips-box"><divref="content"class="tips-content":style="tranlateDo?{transition: `all ${tranlateTime}s linear`,transform: `translateX(-${tranlatex}px)`,}:{transform: 'translateX(0)'}">{{ AthenaData.audioList[voiceIndex].label }}</div></div>
data:
data() {return {AthenaData, // 数据musicDisabled: false, // 播放按钮状态audioTemp: null, // 语音对象voiceIndex: 0, // 文字索引tranlateDo: false, // 文字滚动状态tranlatex: 0, // 文字滚动距离timeoutTicket: null, // 当前文字voiceTimeoutTicket: null, // 下一段文字};},
mounted:
mounted() {// 设置语音播放列表this.audioTemp = new Audio(AthenaData.audioList[0].voice);this.audioTemp.onended = () => {this.musicDisabled = false;this.audioTemp.pause();this.audioTemp.load();this.tranlateDo = false;this.voiceIndex = 0;clearTimeout(this.voiceTimeoutTicket);};// 切到后台停止语音document.addEventListener('visibilitychange', () => {if (document.hidden) {this.musicDisabled = false;this.audioTemp.pause();this.tranlateDo = false;this.voiceIndex = 0;this.audioTemp.load();if (this.timeoutTicket) {clearTimeout(this.timeoutTicket);}clearTimeout(this.voiceTimeoutTicket);}});},
computed: {// 读当前文字滚动的时间tranlateTime() {// 三目运算符容错return AthenaData.audioList[this.voiceIndex]? AthenaData.audioList[this.voiceIndex].time - 1// 每段语音的首末有半秒背景音乐: 1;},},
methods:
methods: {// 播放语音按钮回调onBgmMusicClick() {this.musicDisabled = !this.musicDisabled;if (this.musicDisabled && AthenaData.audioList.length) {this.audioTemp.play();this.setLabelPlay();}if (!this.musicDisabled) {this.audioTemp.pause();this.tranlateDo = false;this.voiceIndex = 0;this.audioTemp.load();if (this.timeoutTicket) {clearTimeout(this.timeoutTicket);}clearTimeout(this.voiceTimeoutTicket);}},//设置文字动画setLabelPlay() {// 语音有半秒前奏播放完后 再开始文字动画this.timeoutTicket = setTimeout(() => {this.tranlateDo = true;this.tranlatex = this.$refs.content.offsetWidth - this.$refs.box.offsetWidth;}, 500);clearTimeout(this.voiceTimeoutTicket);this.voiceTimeoutTicket = setTimeout(() => {
// 目前只有三段文字,若索引为2说明到最后一段,置0停掉动画;否则处理下一段(+1后则显示下一段文字)this.voiceIndex = this.voiceIndex === 2 ? 0 : this.voiceIndex + 1;
// 以下为控制下一段文字动画的逻辑if (this.voiceIndex !== 0) {
// 停掉动画 从头滚动this.tranlateDo = false;this.tranlatex = 0;
// 开始滚动this.setLabelPlay();} else {clearTimeout(this.voiceTimeoutTicket);}}, parseInt(AthenaData.audioList[this.voiceIndex].time, 10) * 1000); // 这个时间为当前动画持续的时间},}
最终效果如下,资源链接
屏幕录制2022-07-28 18.51.06
其实,不难发现,语音和文字的单独控制,只不过是卡住时间让效果看起来是同步。除此之外,还可以扩充暂停功能:播放语音中途点击按钮让语音和文字滚动暂停,再次点击时接着上述效果。原生实现方法只需增加一个变量记录点击时文字已滚动的距离,然后再次点击时进行判断,让动画接着滚动;如果引入其他动画库也许会有直接的API控制动画的暂停,实现起来更加简单。
Audio介绍
什么?你不知道audio是什么?它是h5新特性之一,audio可以理解为普通的dom对象,相关属性方法事件如下:
Audio对象的属性
Audio对象的方法
Audio对象的事件
事件和方法很像,只不过是可以传入回调函数增加更多逻辑
安卓机调用 audio.play()时 报错:API can only be initiated by a user gesture相关推荐
- 在visual studio 2010+中调用ffmpeg编译时 报错error LNK xxxx: 模块对于 SAFESEH 映像是不安全的。...
解决该错误的方法: 1.右键单击该项目选择"属性". 2.在属性页中选择:配置选项->链接器->命令行. 3. 在命令行的"其他选项"中输入/SAF ...
- c# 传递Null的string值导致的调用C++的dll报错 Attempted to read or write protected memory.
c# 调用C++的dll报错 Attempted to read or write protected memory: 原因是:c# 传递Null的string值导致的,将Null改为string.e ...
- Windos环境下kafka配置启动Zookeeper时,报错:Invalid config, exiting abnormally.
Windos环境下kafka配置启动ZooKeeper时,报错:Invalid config, exiting abnormally. 执行命令: D:\kafkaOnWindows\kafka_2. ...
- C# 调用NationalInstruments的dll报错问题 未能加载文件或程序集
C# 调用NationalInstruments的dll报错问题 问题原因:dll版本不匹配导致的,需要做如下操作解决问题 未能加载文件或程序集"NationalInstruments.Co ...
- 调用webservice接口,报错:(十六进制值0x01)是无效的字符。
文章目录 #事故现场 #分析 #解决方法 #事故现场 调用webservice接口,报错:(十六进制值0x01)是无效的字符. 如图: 意思是webservice返回的信息中包含无效的字符,无法解析成 ...
- jni调用 kotlin 方法是报错 kotlin An operation is not implemented: Not yet implemented
项目场景: 提示:这里简述项目相关背景: jni 调用 kotlin中方法会报错 问题描述 TODO("Not yet implemented") 没有去掉代码: override ...
- linux执行.sh文件时,报错:XXX.sh: Permission denied(没有权限)
linux执行.sh文件时,报错:XXX.sh: Permission denied(没有权限) 解决方法:修改对该文件的权限 例如报错: bash: ./zkServer.sh: Permissio ...
- gpt磁盘标签linux,解决安装CentOS6.5时 报错 提示“sda 必须有一个GPT磁盘标签”
解决安装CentOS6.5时 报错 提示"sda 必须有一个GPT磁盘标签" 今天想在thinkpad t430u上安装CentOS6.5 时总共遇到了两个问题 1> u盘安 ...
- RF踩坑之调用pyautogui鼠标操作报错
因为要用到拖拽页面元素,但是robotframework 自带的drag and drop方法无法运行但不报错. 百度说是selenium 的darg and drop 不支持html5. 只能自己调 ...
- 调用微信的接口报错errcode: 40164 invalid ip
调用微信的接口报错errcode: 40164 调用微信的接口报错 { errcode: 40164, errmsg: 'invalid ip 117.100.47.169 ipv6 ::ffff:1 ...
最新文章
- Java基础看这一篇就够了
- element input 只能输入数字_Python之input()函数
- cocos 报错dts文件未导入_cocos2dx 3.4项目 导入到 eclipse 爬过的坑
- BugkuCTF-MISC题隐写3
- java队列实现限流,java中应对高并发的两种策略
- python函数降低编程复杂度_Python-面向对象编程
- android每秒 1,在Android 5.1中调度每秒的警报
- 输入框设置等宽字体_Glyphs 官方教程 | 字体命名
- 用python简单代码做一个计算器
- elipse下载安装教程
- 小米路由器R1C或R1CM小米R1C 原厂Bootloader和epproom
- 阅读HashMap(1.6)源码所做的一些记录
- c++ 11 原子操作库 (std::atomic)(三)
- TPLINK免驱版网卡插上后无法识别到CD驱动器怎么办?
- Bacteria(优先队列)
- 前端的Vue相关的项目经验
- 干货 | 科研必备的软件神器
- 项目管理(PMP)真题解析(二)
- 轻松省力清洁地面,分分钟搞定家务,云米智能洗地机Cyber Lite体验
- 【python】什么是python?python有什么用?
热门文章
- 关于计算机的发展史手抄报图片,历史手抄报精选图片内容
- C++中带.h与不带.h的头文件
- Lounge Lizard EP-4 for Mac(电钢琴插件)v4.2.5破解版
- 用javascript 判断IE窗口是否打开
- Kafka原理介绍+安装+基本操作
- 炒币玩波段为什么一定要设置止损止盈?
- 奋斗在美国湾区,码农的生活
- 华为发放20亿元奖金,抗击美国断供,奖励员工加班奋斗,网友:他们应得的...
- OpenStack之Live-migration
- 十大流行开源软件推荐