从零实现 uni-app 鸿蒙平台 TTS 插件:UTS 开发实践指南
随着移动应用的日益普及,文本转语音(TTS)功能已经成为提升用户体验的重要组成部分。在跨平台开发中,我们常常需要为不同平台提供一致的语音合成能力。
uni-app框架在安卓和IOS提供speech能力,但在鸿蒙(HarmonyOS)平台上,不提供speech支持。本文将详细介绍如何通过UTS技术开发一个鸿蒙平台的TTS插件,弥补这一功能空白,并学习如何实现跨平台接口的一致性。
一、项目概述
本项目将开发一个名为Lime TTS的基于UTS(Uni TypeScript)的文本转语音插件,主要目标是为uni-app在鸿蒙平台上提供语音合成能力。通过本项目的学习,我们将掌握如何使用UTS技术调用鸿蒙原生API,实现跨平台插件开发的核心技能。
二、项目目录结构
我们的Lime TTS项目采用标准的uni-app UTS插件结构,清晰地分离了接口定义和平台实现。这种结构设计有助于我们组织代码,并确保跨平台实现的一致性。项目的目录结构如下:
uni_modules/
└── lime-tts/
├── changelog.md
├── package.json
├── readme.md
└── utssdk/
├── app-android/
│ ├── config.json
│ └── index.uts
├── app-harmony/
│ ├── config.json
│ └── index.uts
├── app-ios/
│ ├── config.json
│ └── index.uts
├── interface.uts
├── unierror.uts
└── web/
└── index.uts
- utssdk/interface.uts:定义了插件的公共接口和类型,是插件的核心规范文件。
- utssdk/app-harmony/index.uts:鸿蒙平台的具体实现代码。
三、接口设计与定义
3.1 核心接口和类型设计
Lime TTS 插件通过 uni_modules/lime-tts/utssdk/interface.uts 文件定义了一套完整的类型和接口规范,确保了良好的类型安全性和代码提示。
语音合成选项
export type SpeakOptions = {
/**
* 语速
* 可选,支持范围 [0.5-2],默认值为 1
*/
speed ?: number;
/**
* 音量
* 可选,支持范围 [0-2],默认值为 1
*/
volume ?: number;
/**
* 音调
* 可选,支持范围 [0.5-2],默认值为 1
*/
pitch ?: number;
/**
* 语境,播放阿拉伯数字用的语种
* 可选,支持 "zh-CN" 中文与 "en-US" 英文,默认 "zh-CN"
*/
language ?: Language;
// 其他配置项...
}
音色信息
export type VoiceInfo = {
language : Language;
person : number;
name : string;
gender : 'male' | 'female';
description : string;
status : 'available' | 'downloadable' | 'unavailable';
}
语音状态
export type SpeechStatus = 'idle' | 'speaking' | 'paused' | 'uninitialized';
3.2 主要功能接口
export interface LimeTTS {
/**
* 朗读指定文本
* @param text 要朗读的文本
* @param options 可选参数,如语音ID、语速等
*/
speak(text : string) : void;
speak(text : string, options : SpeakOptions | null) : void;
/**
* 停止当前朗读
*/
stop() : void;
/**
* 暂停当前朗读
*/
pause() : void;
/**
* 获取可用语音列表
*/
getVoices() : Promise<VoiceInfo[]>;
/**
* 获取当前语音状态
*/
getStatus() : SpeechStatus;
/**
* 销毁TTS实例,释放资源
*/
destroy() : void;
/**
* 监听TTS事件
* @param event 事件类型
* @param callback 回调函数
*/
on(event : 'start' | 'end' | 'error' | 'stop', callback : SpeechCallback) : void;
off(event : 'start' | 'end' | 'error' | 'stop') : void;
off(event : 'start' | 'end' | 'error' | 'stop', callback : SpeechCallback | null) : void;
}
四、鸿蒙平台实现详解
在本节中,我们将详细学习如何为鸿蒙平台实现TTS功能。我们将通过调用鸿蒙原生的@kit.CoreSpeechKit来实现语音合成,并遵循之前设计的接口规范。
4.0 模块导入
在鸿蒙平台实现中,首先需要导入鸿蒙系统提供的核心语音合成模块:
// 导入鸿蒙语音合成相关模块
import { textToSpeech } from '@kit.CoreSpeechKit';
import { BusinessError } from '@kit.BasicServicesKit';
// 导入公共接口定义
import { LimeTTS, SpeakOptions, VoiceInfo, SpeechStatus, SpeechCallback } from '../interface.uts';
4.1 核心实现类
在uni_modules/lime-tts/utssdk/app-harmony/index.uts文件中,定义了LimeTTSImpl类,该类是鸿蒙平台上TTS功能的核心实现:
class LimeTTSImpl implements LimeTTS {
private engine : textToSpeech.TextToSpeechEngine | null = null;
private currentVoice : textToSpeech.CreateEngineParams | null = null;
private eventListeners : Map<string, Array<SpeechCallback>> = new Map<string, Array<SpeechCallback>>();
private isSpeaking : boolean = false;
private isPaused : boolean = false;
// ...
}
4.2 引擎初始化
在构造函数中,插件会初始化 TTS 引擎并设置相关回调:
private initialize(options : CreateEngineParams | null) {
// 清理旧引擎
if (this.engine) {
this.engine.shutdown();
}
const params : textToSpeech.CreateEngineParams = {
language: options?.language ?? 'zh-CN',
person: options?.person ?? 0,
online: 1
}
this.currentVoice = params
const _this = this
textToSpeech.createEngine(params).then((res : textToSpeech.TextToSpeechEngine) => {
this.engine = res
// 设置speak的回调信息
let speakListener : textToSpeech.SpeakListener = {
// 开始播报回调
onStart(requestId : string, response : textToSpeech.StartResponse) {
_this.isSpeaking = true;
_this.isPaused = false;
_this.emit('start', { type: 'start' })
},
// 其他回调...
};
this.engine.setListener(speakListener);
}).catch((err : BusinessError) => {
console.error(`Failed to create engine. Code: ${err.code}, message: ${err.message}.`);
});
}
4.3 文本朗读功能
speak(text : string) : void
speak(text : string, options : SpeakOptions | null = null) {
const extraParams : ESObject = {
speed: options?.speed ?? 1,
volume: options?.volume ?? 1,
pitch: options?.pitch ?? 1,
languageContext: options?.language ?? 'zh-CN'
} as ESObject
this.engine?.speak(text, {
requestId: this.generateRequestId(),
extraParams
} as textToSpeech.SpeakParams);
}
4.4 音色管理
插件实现了音色列表获取和映射功能,将鸿蒙系统的原生音色信息转换为统一格式:
async getVoices() : Promise<VoiceInfo[]> {
try {
if (this.engine) {
// 使用引擎实例查询
const queryParams : textToSpeech.VoiceQuery = {
requestId: this.generateRequestId('voice_query'),
online: 1
};
const voices = await this.engine.listVoices(queryParams);
return this.mapToVoiceInfo(voices);
} else {
// 使用全局方法查询
const queryParams : textToSpeech.VoiceQuery = {
requestId: this.generateRequestId('voice_query'),
online: 1
};
const voices = await textToSpeech.listVoices(queryParams);
return this.mapToVoiceInfo(voices);
}
} catch (error) {
console.error('Failed to get voices:', error);
return Promise.resolve([])
}
}
private mapToVoiceInfo(voices : textToSpeech.VoiceInfo[]) : VoiceInfo[] {
return voices.map(voice => {
// 根据 person 值映射音色名称
let name = 'Unknown';
let gender : 'male' | 'female' = 'female';
switch (voice.person) {
case 0:
case 13:
name = '聆小珊';
gender = 'female';
break;
case 21:
name = '凌飞哲';
gender = 'male';
break;
case 8:
name = 'Laura';
gender = 'female';
break;
}
return {
language: voice.language.replace('_', '-'),
person: voice.person,
name: name,
gender: gender,
description: voice.description || `${name} ${gender === 'male' ? '男声' : '女声'}`,
status: voice.status === 'INSTALLED' ? 'available' :
voice.status === 'GA' ? 'downloadable' : 'unavailable'
} as VoiceInfo;
});
}
五、测试与验证
在开发完成插件后,我们需要编写测试代码来验证功能是否正常工作。以下是一个用于测试Lime TTS插件的代码示例:
// 导入我们开发的 TTS 工具函数
import { useTTS } from '@/uni_modules/lime-tts'
// 创建 TTS 实例 - 测试实例化功能
const tts = useTTS();
// 设置事件监听 - 测试事件机制
// 播放开始事件
const onStart = (event) => {
console.log('语音播放开始');
};
// 播放结束事件
const onEnd = (event) => {
console.log('语音播放结束');
};
// 错误处理事件
const onError = (event) => {
console.error('语音播放错误:', event);
};
// 注册事件监听器
tts.on('start', onStart);
tts.on('end', onEnd);
tts.on('error', onError);
// 测试核心功能 - 文本朗读
tts.speak('欢迎使用 Lime TTS 插件!', {
speed: 1.0, // 语速
volume: 1.0, // 音量
pitch: 1.0 // 音调
});
// 测试控制功能
setTimeout(() => {
// 测试暂停功能
tts.pause();
}, 3000);
// 测试状态查询功能
const status = tts.getStatus();
console.log('当前语音状态:', status);
// 测试音色管理功能
tts.getVoices().then(voices => {
console.log('可用音色列表:', voices);
});
// 测试资源释放 - 在组件卸载时调用
const cleanup = () => {
// 移除事件监听器
tts.off('start', onStart);
tts.off('end', onEnd);
tts.off('error', onError);
// 销毁实例,释放系统资源
tts.destroy();
};
六、鸿蒙平台特别说明
在鸿蒙平台上,Lime TTS 插件支持以下音色:
- 中文女声:聆小珊(person: 13,推荐使用)
- 中文男声:凌飞哲(person: 21,需要下载)
- 英文女声:Laura(person: 8,需要下载)
七、总结
通过本文的学习,我们详细了解了如何使用UTS技术为uni-app开发鸿蒙平台的TTS插件。这个过程涵盖了从接口定义、模块导入到核心功能实现的完整开发流程,展示了如何通过调用鸿蒙原生的@kit.CoreSpeechKit能力,弥补uni-app在鸿蒙平台上speech API缺失的问题。
开发鸿蒙平台插件的关键要点包括:
- 设计统一的跨平台接口,确保API一致性
- 正确导入鸿蒙系统模块,如
@kit.CoreSpeechKit和@kit.BasicServicesKit - 实现核心功能类,处理平台特定的API细节
- 封装事件监听机制,提供良好的开发者体验
- 处理音色映射和状态管理,确保功能完整性
希望本文能为您学习如何开发uni-app鸿蒙插件提供有价值的参考,帮助您掌握UTS开发技术,为uni-app生态贡献更多优质的平台适配插件。
目前,本插件已上传至uni-app插件市场,全面支持uni-app和uni-appx框架,并兼容安卓、鸿蒙和Web三大平台,iOS平台将在稍晚上线。开发者可以直接在项目中集成使用,体验跨平台的TTS功能。lime-tts
0 个评论
要回复文章请先登录或注册