ArkTS使用 音振协同 制作单例音振播放功能
在开发《硬要写》app过程中,处理按键、提醒音效和振动时,我没有再使用soundpool+vibrator的组合,改用了音振协同。代码量减少,管理更清晰。协同会同时开始音乐和振动。4. 新建vibrator.json,保存至resources -> rawFile文件夹。- 使用rawfile文件夹中的mp3和震动马达json;我将代码整理出来,供大家使用。- 使用单例类实现全局音振;- 调用简单
·

在开发《硬要写》app过程中,处理按键、提醒音效和振动时,我没有再使用soundpool+vibrator的组合,改用了音振协同。代码量减少,管理更清晰。协同会同时开始音乐和振动。
我将代码整理出来,供大家使用。
@ohos.multimedia.audioHaptic
- 使用rawfile文件夹中的mp3和震动马达json;
- 使用单例类实现全局音振;
- 调用简单,快捷;
1. module.json5中增加权限:
"name": "ohos.permission.VIBRATE"
2. 新建单例类AudioHapticService.ets:
import { audioHaptic } from '@kit.AudioKit';
import { BusinessError, emitter } from '@kit.BasicServicesKit';
// 音频文件名称,需要在rawfile目录下
const audioName:string = 'music_end_default.mp3';
// 振动文件名称,需要在rawfile目录下
const vibratorName:string = 'vibrator.json';
// 音频振动服务事件
export const AudioHapticServiceEvt:string = 'endOfStream';
/**
* 音频和触觉服务
*/
export class AudioHapticService {
//单例部分
private static instance: AudioHapticService | undefined = undefined;
static getInstance(): AudioHapticService {
if (!AudioHapticService.instance) {
AudioHapticService.instance = new AudioHapticService();
}
return AudioHapticService.instance;
}
private constructor() {}
// 音频ID,用于注销
private ahId :number | undefined = undefined;
// 音频振动播放器
private audioHapticPlayer: audioHaptic.AudioHapticPlayer | undefined = undefined;
// 播放状态
private playing: boolean = false
// 初始化音频和振动
async initAudioHaptic(context:Context){
// 获取音频振动管理器
let ahManager = audioHaptic.getAudioHapticManager();
try {
// 注册音频文件
let audioFile = context.resourceManager.getRawFdSync(audioName);
let audioFd : audioHaptic.AudioHapticFileDescriptor = {
fd: audioFile.fd,
offset: audioFile.offset,
length: audioFile.length,
};
// 注册振动文件
let hapticFile = context.resourceManager.getRawFdSync(vibratorName);
let hapticFd: audioHaptic.AudioHapticFileDescriptor = {
fd: hapticFile.fd,
offset: hapticFile.offset,
length: hapticFile.length,
};
// 注册音频和振动文件
this.ahId = await ahManager.registerSourceFromFd(audioFd,hapticFd);
// 创建音频振动播放器
this.audioHapticPlayer = await ahManager.createPlayer(this.ahId,{muteAudio: false, muteHaptics: false});
// 关闭音频和振动文件描述符,避免内存泄漏
context.resourceManager.closeRawFdSync(audioName);
context.resourceManager.closeRawFdSync(vibratorName);
// 注册音频振动播放器事件,当音频播放结束时,触发事件
this.audioHapticPlayer.on('endOfStream', () => {
console.info(`Receive the callback of endOfStream.`);
// 广播音振结束事件
emitter.emit(AudioHapticServiceEvt);
});
} catch (error) {
throw error as Error;
}
}
/**
* 开始播放音频和振动
*/
async startEndNotify(){
if(this.audioHapticPlayer){
try {
await this.audioHapticPlayer.start()
this.playing = true;
} catch (err) {
const be: BusinessError = err as BusinessError
console.error(`AudioHaptic start failed: ${be.code}, ${be.message}`)
}
}
}
/**
* 停止播放音频和振动
*/
async stopEndNotify(){
if (!this.audioHapticPlayer) {
return;
}
try {
await this.audioHapticPlayer.stop()
this.playing = false;
} catch (err) {
const be: BusinessError = err as BusinessError
console.error(`AudioHaptic stop failed: ${be.code}, ${be.message}`)
}
}
/**
* 释放音频和振动播放器
*/
release(){
if(this.audioHapticPlayer){
this.audioHapticPlayer.release().then(() => {
this.playing = false;
console.info(`Promise returned to indicate that start playing successfully.`);
}).catch((err: BusinessError) => {
console.error(`Failed to start playing. ${err}`);
});
}
}
/**
* 查询是否正在播放
*/
isPlaying(): boolean {
return this.playing
}
}
3. 打开EntryAbility.ets 在onCreate中插入单例初始化代码:
async onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): Promise<void> {
// 初始化单例
AudioHapticService.getInstance().initAudioHaptic(this.context);
}
4. 新建vibrator.json,保存至resources -> rawFile文件夹
{
"MetaData": {
"Create": "2025-12-11",
"Description": "音振协同,震动2秒且短促有力",
"Version": 1.0,
"ChannelNumber": 1
},
"Channels": [
{
"Parameters": {
"Index": 0
},
"Pattern": [
{
"Event": {
"Type": "continuous",
"StartTime": 0,
"Duration": 2000,
"Parameters": {
"Frequency": 30,
"Intensity": 80,
"Curve": [
{
"Time": 0,
"Frequency": 0,
"Intensity": 0
},
{
"Time": 250,
"Frequency": 12,
"Intensity": 0.5
},
{
"Time": 500,
"Frequency": -8,
"Intensity": 1.0
},
{
"Time": 750,
"Frequency": 0,
"Intensity": 0
},
{
"Time": 1000,
"Frequency": 0,
"Intensity": 0
},
{
"Time": 1250,
"Frequency": 20,
"Intensity": 0.5
},
{
"Time": 1500,
"Frequency": 25,
"Intensity": 1.0
},
{
"Time": 1750,
"Frequency": 20,
"Intensity": 1
}
]
}
}
}
]
}
]
}
5. 在任意代码位置,使用音振协同:
Button('play AudioHaptic').onClick(()=>{
// 播放音乐和震动
AudioHapticService.getInstance().startEndNotify();
})
Button('stop AudioHaptic').onClick(()=>{
// 停止音乐和震动
AudioHapticService.getInstance().stopEndNotify();
})
注意:
- 自备音乐.mp3文件,音乐可以和震动频率不一样长,比如音乐10分钟,震动2秒。
- 我使用的是registerSourceFromFd需要api 20+,低api可以改用registerSource。
更多推荐



所有评论(0)