支持,以web后台播放音频为例。
【解决方案】
系统为了省电和稳定,会强制终止H5的后台行为,Web组件要实现音频后台播放,必须通过“长时任务”向系统申请许可,否则用户一退到后台,音频就会停止播放。
实现步骤如下:
- 需要module.json5中配置ohos.permission.KEEP_BACKGROUND_RUNNING权限。
{
"module" : {
// To do sth.
"requestPermissions":[
{
"name": "ohos.permission.KEEP_BACKGROUND_RUNNING",
"reason": "$string:reason",
"usedScene": {
"abilities": [
"FormAbility"
],
"when":"inuse"
}
}
]
}
}
- 声明后台模式类型。
在module.json5文件中为需要使用长时任务的UIAbility声明相应的长时任务类型,配置文件中填写长时任务类型的配置项。音频、视频在后台播放需配置为audioPlayback。
"module": {
"abilities": [
{
"backgroundModes": [
// 长时任务类型的配置项
"audioPlayback"
]
}
],
// To do sth.
}
- 如果应用本身没有后台播放业务,可以通过监听生命周期函数onBackground来判断应用是否已进入后台。
在EntryAblity.ets中的回调中获取前后台的状态,通过AppStorage将状态保存,然后在Web页面通过@Watch来监听变量的变化。
export default class EntryAbility extends UIAbility {
onForeground(): void {
// 切到前台,设置isForeGround值为true
AppStorage.setOrCreate('isForeGround', true);
}
onBackground(): void {
// 切到后台,设置isForeGround值为false
AppStorage.setOrCreate('isForeGround', false)
}
}
- 在Web加载H5音频页面并创建长时任务。
注意:创建wantAgent.WantAgentInfo时添加需要被拉起应用的bundleName和abilityName。
import { webview } from '@kit.ArkWeb'
import { backgroundTaskManager } from '@kit.BackgroundTasksKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { wantAgent, WantAgent } from '@kit.AbilityKit';
@Entry
@Component
export struct WebAudioPage {
// 通过getUIContext().getHostContext()方法,来获取page所在的UIAbility上下文
private context: Context | undefined = this.getUIContext().getHostContext();
controller: webview.WebviewController = new webview.WebviewController()
// 启动长时任务的函数(独立函数,避免this指向错误)
// 监听isForeGround的值
[@Watch](/user/Watch)('network') @StorageLink('isForeGround') isForeGround: boolean = false;
network() {
// 切换到前台了,视频播放
if (this.isForeGround) {
this.stopContinuousTask()
} else {
// 切换到后台了,视频停止播放
this.startContinuousTask()
}
}
startContinuousTask() {
// 指定任务类型为audioPlayback
const taskTypes = ["audioPlayback"];
// 指定要启动的Ability(EntryAbility)
let wantAgentInfo: wantAgent.WantAgentInfo = {wants: [{
bundleName: "com.example.xxx", // 替换为你的实际包名
abilityName: "EntryAbility",
}],
actionType: wantAgent.OperationType.START_ABILITY,
// 使用者自定义的一个私有值
requestCode: 0,
// 点击通知后,动作执行属性
actionFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG],
};
try {
wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj) => {
backgroundTaskManager.startBackgroundRunning(this.context, taskTypes, wantAgentObj)
.then((res: backgroundTaskManager.ContinuousTaskNotification) => {
console.info('长时任务启动成功,音频将在后台持续播放');
})
.catch((error: BusinessError) => {
console.error(`启动长时任务失败: code=${error.code}, message=${error.message}`);
});
}).catch((error: BusinessError) => {
console.error('获取 WantAgent 失败:', error);
});
} catch (error) {
console.error('异常:', error);
}
}
stopContinuousTask() {
backgroundTaskManager.stopBackgroundRunning(this.context).then(() => {
console.info(`Succeeded in operationing stopBackgroundRunning.`);
}).catch((err: BusinessError) => {
console.error(`Failed to operation stopBackgroundRunning. Code is ${err.code}, message is ${err.message}`);
});
}
build() {
Column() {
Web({
src: $rawfile('audio.html'),
controller: this.controller
})
.domStorageAccess(true)
}
.width('100%')
.height('100%')
}
}
audio.html代码如下:
<!DOCTYPE html>
<html lang="zh">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
<meta charset="UTF-8" />
<title>音频播放测试</title>
</head>
<body>
<h2>点击播放音频</h2>
<audio id="myAudio" controls autoplay loop>
<source src="audio.mp3" type="audio/mpeg">
</audio>
<script>
// 防止自动播放被拦截,建议用户交互后播放
document.getElementById('myAudio').addEventListener('click', function () {
this.play().catch(e => console.error('播放被阻止:', e));
});
</script>
</body>
</html>
【背景知识】
ArkWeb:用于在应用程序中显示Web页面内容。
长时任务:应用退至后台后,在后台需要长时间运行用户可感知的任务,如播放音乐、导航等。为防止应用进程被挂起,导致对应功能异常,可以申请长时任务,使应用在后台长时间运行。在长时任务中,支持同时申请多种类型的任务,也可以对任务类型进行更新。应用退至后台执行业务时,系统会做一致性校验,确保应用在执行相应的长时任务。
应用在申请长时任务成功后,通知栏会显示与长时任务相关联的消息,用户删除通知栏消息时,系统会自动停止长时任务。