项目为使用uniapp框架开发的Android/iOS APP应用

实现功能需求

假设手机正在播放音乐,当前APP处于前台收到消息,需播放提示音提示用户。目标为降低后台正在播放音乐的音量,播放提示音,播放完毕后恢复后台音乐音量

需求分析

乍一看,需求看似很简单,实则以目前uni官方所封装的API根本无法实现,附上链接uni.createInnerAudioContext,该API中的sessionCategory配置,实则为当前APP的音频模式,播放的时候影响到其他APP的行为只有一个结果——暂停
很明显,这并非我们能接受的结果,只能另寻他路,既然uni不行,那就只能靠native.js调用原生方法了

查阅文档

博主找遍了uni官方的文档、论坛,找不到任何相关的功能实现文章。无奈,只能查原生文档,Android、iOS,在阅读了大量原生实现文章后,注意到一个关键词——音频焦点,就是说后续的编码均是围绕着音频焦点而开展的

Android端

Android端的实现,需要使用到AudioManagerMediaPlayerAudioAttributes这三个类,首先AudioManager实例需要使用Context去获取

MediaPlayer类则直接import后new一个新实例就可以了,AudioAttributes则用来设置所播放音频的属性。最后,还有一个音频播放结束后释放音频焦点的监听方法,这个在Java中为Interface接口方法——MediaPlayer.OnCompletionListener
参考链接:AudioManager类、MediaPlayer类、AudioAttributes类、
MediaPlayer.OnCompletionListener接口

<script>
export default {data() {return {audioManager: null, // 音频管理innerAudioContext: {}, // 播放器实例audioFocus: false // 音频焦点}},created() {this.buildAudio();},methods: {buildAudio() {let path = plus.io.convertLocalFileSystemURL('xxx/voice.mp3');if (this.$store.state.platform == 'android') {// Android端// 导入声音管理类(必须步骤,不引会导致功能无法正常运行)plus.android.importClass('android.media.AudioManager');let main = plus.android.runtimeMainActivity(); // 获取应用主Activity实例对象let Context = plus.android.importClass('android.content.Context'); // 全局上下文this.audioManager = main.getSystemService(Context.AUDIO_SERVICE);let MediaPlayer = plus.android.importClass('android.media.MediaPlayer');let AudioAttributes = plus.android.importClass('android.media.AudioAttributes');this.innerAudioContext = new MediaPlayer();// Android中的接口实现使用plus.android.implements,注意接口名称类与接口方法之间要用符号$连接let event = plus.android.implements('android.media.MediaPlayer$OnCompletionListener', {onCompletion: () => {if (this.audioFocus) {this.audioManager.abandonAudioFocus(null); // 放弃音频焦点this.audioFocus = false;}}});this.innerAudioContext.setOnCompletionListener(event); // 设置播放完毕监听this.innerAudioContext.setDataSource(path); // 设置播放器播放音频this.innerAudioContext.setAudioAttributes(AudioAttributes.CONTENT_TYPE_SONIFICATION); // 设置音频属性,CONTENT_TYPE_SONIFICATION为短暂提示音this.innerAudioContext.prepare();} else {// iOS端...}}}
}
</script>

需要播放音频时,则判断一下后台是否播放着音乐,若正在播放,则请求音频焦点,设置系统类型为音乐类型(STREAM_MUSIC),设置持续时间提示为短暂打断模式(AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK

if (this.$store.state.platform === 'android') {// Android端if (this.audioManager.isMusicActive()) {// 判断是否正在播放音乐this.audioFocus = true;this.audioManager.requestAudioFocus(null, this.audioManager.STREAM_MUSIC, this.audioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK); // 请求音频聚焦}this.innerAudioContext.start(); // 播放
} else {// iOS端...
}

iOS端

iOS端的实现,需要用到AVAudioSessionNSDataAVAudioPlayer这三个类,其中AVAudioSession需要使用sharedInstance获取分享音频会话实例

NSData用于转换本地文件路径为二进制数据,供AVAudioPlayer类实例用于初始化播放器。最后,还需要挂载播放完毕的代理方法AVAudioPlayerDelegate,用于在音频播放结束后设置音频会话激活状态(相当于Android端的释放音频焦点)为false
参考链接:AVAudioSession类、AVAudioPlayer类、NSData类、
AVAudioPlayerDelegate代理

<script>
export default {methods: {buildAudio() {let path = plus.io.convertLocalFileSystemURL('xxx/voice.mp3');if (this.$store.state.platform == 'android') {// Android端...} else {// iOS端let AVAudioSession = plus.ios.importClass('AVAudioSession');this.audioManager = AVAudioSession.sharedInstance(); // 获取分享音频会话实例/*** 设置音频会话类型为AVAudioSessionCategoryPlayback,同时配置选项为AVAudioSessionCategoryOptionMixWithOthers和AVAudioSessionCategoryOptionDuckOthers* Constants that specify optional audio behaviors. setCategory:withOptions:error* setCategory:(AVAudioSessionCategory)category:* @param AVAudioSessionCategoryPlayback The category for playing recorded music or other sounds that are central to the successful use of your app.* withOptions:(AVAudioSessionCategoryOptions)options:* @param AVAudioSessionCategoryOptionMixWithOthers = 0x1 An option that indicates whether audio from this session mixes with audio from active sessions in other audio apps.* @param AVAudioSessionCategoryOptionDuckOthers = 0x2 An option that reduces the volume of other audio sessions while audio from this session plays.*/this.audioManager.setCategorywithOptionserror('AVAudioSessionCategoryPlayback', 0x1 | 0x2, null);let NSData = plus.ios.importClass('NSData');let AVAudioPlayer = plus.ios.importClass('AVAudioPlayer');let pathFileData = NSData.dataWithContentsOfFile(path); // 音频文件转为二进制数据this.innerAudioContext = new AVAudioPlayer(); // new一个音频播放器实例this.innerAudioContext.initWithDataerror(pathFileData, null); // 初始化数据// iOS中挂载代理方法使用plus.ios.implements,注意挂载的方法名需一个字符不差写完整audioPlayerDidFinishPlaying:successfully:let delegate = plus.ios.implements('AVAudioPlayerDelegate', {'audioPlayerDidFinishPlaying:successfully:': () => {if (this.audioFocus) {/*** 设置音频会话激活状态(相当于Android端的音频焦点)为false,同时配置选项为AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation,用于通知其他被中断的APP恢复播放* Activates or deactivates your app’s audio session using the specified options. setActive:withOptions:error* setActive:(BOOL)active:* Specify YES to activate your app’s audio session, or NO to deactivate it.(Objective-C中的YES相当于JS的true,NO相当于false)* withOptions:(AVAudioSessionSetActiveOptions)options:* @param AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation = 1 An option that indicates that the system should notify other apps that you’ve deactivated your app’s audio session.*/this.audioManager.setActivewithOptionserror(false, 1, null);this.audioFocus = false;}}});this.innerAudioContext.plusSetAttribute('delegate', delegate); // 使用plusSetAttribute设置实例对象属性delegate}}}
}
</script>

接下来是音频播放,跟Android端差不多,iOS端这边是激活音频会话

if (this.$store.state.platform === 'android') {// Android端...
} else {// iOS端if (this.audioManager.plusGetAttribute('isOtherAudioPlaying')) {// 获取判断音频会话属性isOtherAudioPlayingthis.audioFocus = true;this.audioManager.setActiveerror(true, null); // 激活音频会话}this.innerAudioContext.play(); // 播放
}

总结

编码完毕,实际上手调试,在后台其他APP(如音乐播放器)正在播放音乐时,本APP播放提示音,在Android/iOS两端都是表现为降低音乐音量,播放提示音,提示音播放完毕后,恢复音乐音量。
至此,已完美完成需求,这里简单说一下本功能的开发感受:uni官方没有实现的功能,确实通过H5+plus绝大部分功能都是可以实现的,但对于没人写过参考的功能,就只能靠自己查阅原生开发文档、查阅原生开发相关代码,之后尝试使用native.js改写,这整套流程下来,对一个纯前端开发而言确实不容易。但是,博主认为这个过程是收获颇丰的,也是让人有成就感的,毕竟全网第一份。
就说这么多了,Keep learning…

uniapp实现音频播放抢占系统音频焦点相关推荐

  1. Android官方开发文档Training系列课程中文版:管理音频播放之管理音频焦点

    原文地址:http://android.xsoftlab.net/training/managing-audio/audio-focus.html 因为可能会存在多个APP播放音频,所以考虑它们之间的 ...

  2. 创建多媒体APP 之 音频播放:管理音频焦点

    因为很多APP都会潜在需要去播放音频文件,所有要考虑多个APP在播放音频文件的时候会产生的影响,这个非常重要.为了防止同时有多个APP播放音频,android采用了音频焦点这个概念来节制APP对音频的 ...

  3. ios系统html播放音频播放器,iOS音频播放之AVAudioPlayer,AVPlayer,AVQueuePlayer

    本文以婚语APP为例,来讲解集体使用方法. 在婚语APP中,分别使用了AVAudioPlayer,AVPlayer,AVQueuePlayer来实现音频播放功能,下面以婚语的实际需求分别介绍它们的使用 ...

  4. html audio播放本地语音文件,HTML5+ - audio音频播放及网络音频文件播放

    1.介绍常用方法 createPlayer()创建音频对象 play: 开始播放音频 pause: 暂停播放音频 resume: 恢复播放音频 stop: 停止播放音频 seekTo: 跳到指定位置播 ...

  5. 怎样打开计算机音频服务器,win10系统音频服务器未运行的修复步骤

    有关win10系统音频服务器未运行的操作方法想必大家有所耳闻.但是能够对win10系统音频服务器未运行进行实际操作的人却不多.其实解决win10系统音频服务器未运行的问题也不是难事,小编这里提示两点: ...

  6. 有声音显示音频服务器,Win7系统音频服务声音图标显示红叉导致运行失败怎么办【图文】...

    win7系统稳定.安全.人性化的设计深得广大用户的喜爱,在完美的系统操作过程中难免遇到一些故障问题,很多用新安装win7系统后遇到任务栏声音喇叭图标显示红色叉叉,怎么回事呢?出现红色叉叉主要原因是音频 ...

  7. 怎样打开计算机音频服务器,win7系统音频服务器怎么启动 win7电脑音频服务未启动解决方法...

    ‍‍‍‍‍ ‍电脑中的音频服务对于不少用户来说是不可缺少的,最近有用户发现自己电脑的音频服务未运行,那么win7系统音频服务器怎么启动?下面就将具体的启动方法分享给大家.‍ 具体的解决方法: 1.Wi ...

  8. 【音频播放】自制音频播放器—音视频基础概念,未完待续。。。

    近期用Electron制作了一个简易版客户端,未完待补充,重点在播放,引用凯教,先说几点.(图片禁止搬运,不得允许不准转载) 研究音频的数字化技术之前,必须对声音和图像的的物理性质有基本的了解. 如下 ...

  9. java 音频播放器_JAVA音频播放器问题

    代码如下,请高手帮忙解决importjava.applet.*;importjava.awt.*;importjava.awt.event.*;importjava.io.*;importjava.n ...

最新文章

  1. Codeforces Round #228 (Div. 1)B
  2. 互联网老师论坛高调炫耀收入:硕士毕业三年,月入九万多!
  3. Java 地位不保,落后已成定局 ?| 10月编程语言排行
  4. 关于SAP Kyma在国内的落地情况
  5. 2021牛客暑期多校训练营5 D-Double Strings(dp+组合数)
  6. php fetch mode,odbc_fetch_into
  7. html大学生活主题班会,我的大学生活主题班会策划书
  8. (转载)深入理解WeakHashmap
  9. hdu 2546 饭卡 01背包
  10. java+ssm+mysql房屋租赁管理系统(源码+论文)
  11. tomcat乱码问题解决集合
  12. 【裴礼文数学分析】例1.1.2
  13. 高项计算题2-三点估算(计划评审技术PERT),时差,投资回收期,贴现率,沟通渠道
  14. Android使用TextToSpeech实现语音播报-及默认不支持中文的方案
  15. 华为python自动化测试框架_华为五年自动化测试工程详细解说:unittest单元测试框架...
  16. 【opencv学习笔记】025之直方图计算 - calcHist函数详解
  17. 菜鸟学Linux命令:nohup命令启动程序
  18. java 对比度_调整图像亮度、对比度、饱和度
  19. Office总是无响应的解决办法
  20. 汽车之家汽车品牌Logo信息抓取 DotnetSpider实战[三]

热门文章

  1. 编程猫和python区别_西瓜创客和编程猫有什么不同?哪个更值得报名?
  2. luogu P1646 happiness
  3. FLUENT直管流动压力损失仿真分析问题
  4. 走近Gavin King
  5. Delphi 版的 Ping
  6. 盘点物联网架构的4个必要阶段
  7. java zipfile用法_Java使用ZipFile类实现Zip文件解压
  8. 开学季,Gooxi GPU服务器助力建设智慧校园
  9. 笔记:表单验证以及sweetalert中swal的使用
  10. 需要注意选择织梦cms网站模板对于优化方面的问题