更新记录
1.1.6(2023-12-27)
以下为针对上架各家应用商店所做的调整
- 修正耳机初始化监听逻辑,将自动监听改为使用init方法手动监听(应用宝)
- 将sdk版本调整为min26,target33(小米)
以下为相关BUG修复
- 修复无TTS引擎时init方法回调无内容
- 修复安卓版本10以上,在初始化前台服务时应用闪退bug
- 优化修复其他有可能会导致闪退的逻辑
以下为新增内容
- 新增跳转到通知设置页面接口 openNotifySetting()
- 新增检查是否获得通知权限 checkNotifyEnabled()
- 新增来电通话状态监听
1.1.5(2023-03-16)
- 新增跳转到电池保护设置页面接口 goBatterySetting
- 新增跳转到应用自启动设置页面接口 goAutoStartSetting
- 新增创建、停止前台服务 startForeground 、 stopForeground
1.1.4(2023-03-07)
- 新增init后回调内返回引擎包列表
- 新增耳机连接状态监听
平台兼容性
Android | Android CPU类型 | iOS |
---|---|---|
适用版本区间:8.0 - 14.0 | armeabi-v7a:支持,arm64-v8a:支持,x86:支持 | × |
原生插件通用使用流程:
- 购买插件,选择该插件绑定的项目。
- 在HBuilderX里找到项目,在manifest的app原生插件配置中勾选模块,如需要填写参数则参考插件作者的文档添加。
- 根据插件作者的提供的文档开发代码,在代码中引用插件,调用插件功能。
- 打包自定义基座,选择插件,得到自定义基座,然后运行时选择自定义基座,进行log输出测试。
- 开发完毕后正式云打包
付费原生插件目前不支持离线打包。
Android 离线打包原生插件另见文档 https://nativesupport.dcloud.net.cn/NativePlugin/offline_package/android
iOS 离线打包原生插件另见文档 https://nativesupport.dcloud.net.cn/NativePlugin/offline_package/ios
注意事项:使用HBuilderX2.7.14以下版本,如果同一插件且同一appid下购买并绑定了多个包名,提交云打包界面提示包名绑定不一致时,需要在HBuilderX项目中manifest.json->“App原生插件配置”->”云端插件“列表中删除该插件重新选择
文字转语音 - 更新日志
终版(2023-12-22)
注意:此版本为应用商店版,若更新此版本需设置manifest.json中的 APP常用其他设置 -> minSdkVersion = 26,否则无法正常打包。如果需要minSdkVersion = 19版本的,请移步码云:https://gitee.com/lyq617/uniapp-text-to-speech-plugin自取离线包。
此次更新为该版本最后一版,以后非bug问题,不再更新此版本。
新版本重构了通知栏,支持自定义通知图片、通知标题、通知内容,支持通知栏内点击上一首、下一首、播放、暂停按钮事件监听等实用功能,欢迎使用:https://ext.dcloud.net.cn/plugin?id=16025
以下为针对上架各家应用商店所做的调整
- 修正耳机初始化监听逻辑,将自动监听改为使用init方法手动监听(应用宝)
- 将sdk版本调整为min26,target33(小米)
以下为相关BUG修复
- 修复无TTS引擎时init方法回调无内容
- 修复安卓版本10以上,在初始化前台服务时应用闪退bug
- 优化修复其他有可能会导致闪退的逻辑
以下为新增内容
- 新增跳转到通知设置页面接口 openNotifySetting()
- 新增检查是否获得通知权限 checkNotifyEnabled()
- 新增来电通话状态监听
1.1.5(2023-03-07)
- 新增跳转到电池保护设置页面接口 goBatterySetting
- 新增跳转到应用自启动设置页面接口 goAutoStartSetting
- 新增创建、停止前台服务 startForeground 、 stopForeground
1.1.4(2023-03-06)
- 新增init后回调内返回引擎包列表
- 新增耳机连接状态监听
1.1.3(2023-01-28)
- 新增获取设备已安装引擎列表,自定义选择引擎
1.1.2(2022-10-19)
-
修复1.1.1版本更新内容向下兼容
(若不想更新,更新1.1.1版本后无法播放的,需修改init方法,该方法新增了一个参数)
1.1.1(2022-10-09)
- 增加缓存目录管理接口
- 增加音频播放模式,该模式下首先将文字转为音频,然后调用MediaPlayer进行播放,实现暂停、继续功能,同时支持播放进度回显。
1.1.0 (2022-09-29)
- 增加播放进度监听
- 增加获取当前系统默认的语音引擎
1.0.2(2020-01-03)
- 增加语音播放方式: 1 丢弃之前的播报任务,立即播报本次内容; 2 播放完之前的语音任务后才播报本次内容;
- 获取播放进度这个可以实现,只是目前因工作原因时间不是很多,先使用定义播放方式解决文章连续阅读
- TTS一次最大支持字符为4000字,最好将文字分段播放
1.0.1(2019-10-30)
增加保存合成音频
1.0.0(2019-10-24)
中文文字转语音
介绍
TTS(Text To Speech,文本转语音)是语音合成应用的一种,它将储存于电脑中的文件,如帮助文件或者网页,转换成自然语音输出。
使用说明
需要搭配第三方语音引擎实现中文转语音(一般来说手机都会自带语音引擎,如果没有的话可以自行下载安装,讯飞等TTS语音引擎)
测试机型
- 华为MATE20 、华为 MATE20PRO、小米MIX2S、PDA安卓10系统
接口说明
- init(JSCallback jsCallback) 初始化引擎
1.1.1版本:init(JSONObject options, JSCallback jsCallback) options必传。 options.savePath 初始化音频文件保存目录
复制代码 TTSSpeaker.init(
{
savePath: '' // 音频保存目录
},
function(result) {
console.log(result);
// 返回设置的语速和音调
_this.pitch = result.data.voice_pitch;
_this.speed = result.data.voice_speed;
uni.showToast({
title: JSON.stringify(result),
icon: 'none'
});
}
);
1.1.2版本以后:init(JSCallback jsCallback, JSONObject options) options可不传。 options.savePath 初始化音频文件保存目录
复制代码 TTSSpeaker.init(
function(result) {
// 此处注意,需要根据实际返回内容进行json格式判断是否需要parse
// init回调内不可调用任何tts插件方法,如speak、setVoiceSpeed等,因为这些方法全部基于init初始化方法创建的tts对象,此处回调是在init tts对象内,若在此处调用基于tts对象的方法将报错
let obj = JSON.parse(result.data)
// 返回设置的语速和音调
_this.pitch = obj.voice_pitch;
_this.speed = obj.voice_speed;
// 返回当前已安装的引擎列表
_this.engineList = JSON.parse(obj.engines);
_this.engineList.forEach(v => {
_this.array.push(v.app_name)
})
uni.showToast({
title: JSON.stringify(result),
icon: 'none'
});
},
{
savePath: '', // 音频保存目录
engine: engine | 'com.iflytek.speechsuite' // 自定义语音引擎 使用 getEngines 方法返回的 package_name ,留空默认使用设备默认引擎
}
);
-
speak(String words, Integer model, String taskId)
words:待播放的文字 model: 1 丢弃之前的播报任务,立即播报本次内容; 2 播放完之前的语音任务后才播报本次内容; taskid:自定播放任务id,用于监听播放进度回调,id全局唯一,不可重复
-
setVoiceSpeed(Float speed, JSCallback jsCallback) 设置语速,最高为3
-
setVoicePicth(Float speed, JSCallback jsCallback) 设置语调,最高为3(有些手机不支持)
-
stop() 停止播放
-
saveAudioFile(JSONObject options, JSCallback jsCallback) 保存合成音频
-
destorySpeaker() 销毁注册的播放任务
-
getDefaultEngine() 获取当前系统默认语音引擎包名,若为空则说明系统内缺少TTS引擎,需要下载安装(讯飞等)
-
playerSpeak(String words, String savePath, JSCallback jsCallback)音频模式-生成文件并播放,返回文件目录
-
playerPlay(String audioPath); 播放本地音频
-
playerStop() 停止播放
-
playerResume() 恢复播放
-
playerPause() 暂停播放
-
getFolderSize(String path) 递归获取指定目录下总文件大小,留空默认目录为
/storage/emulated/0/Android/data/包名/cache/voices/
-
getCurrentFolderSize(String path) 只获取指定目录下总文件大小,留空默认目录为
/storage/emulated/0/Android/data/包名/cache/voices/
-
deleteFolderFile(String path, Boolean deleteSelf) 递归删除指定目录下的文件夹及文件 deleteSelf:是否同时删除祖目录
-
deleteFile(String path) 删除指定目录下的文件
-
goBatterySetting() 跳转到电池保护设置页面
-
goAutoStartSetting() 跳转到应用自启动设置页面
-
startForeground(String notifyTitle, String notifyContent, String notifyTicker) 创建前台服务
复制代码 notifyTitle:通知标题 默认为应用名
notifyContent:通知简介 默认为 应用名 + 运行中...
notifyTicker:通知提示文本 默认为 应用名 + 运行中...
- stopForeground() 停止前台服务
回调监听
复制代码 const speakListener = weex.requireModule('globalEvent');
// TTS实时模式监听播放状态
speakListener.addEventListener('speakListener', function(e) {
// {"data":{"taskid":"666234324563543","code":1,"msg":"播放开始"},"code":0,"msg":"实时播放任务监听"}
// data.code 1 播放开始 2 播放结束 -1 播放失败
console.log(e);
});
// 文字转音频播放监听播放状态
speakListener.addEventListener('mediaListener', function(e) {
// {"data":{"status":1,"data":{"position":97,"progress":6792},"msg":"正在播放"},"code":0,"msg":"音频模式播放任务监听"}
// data.status 1 正在播放 2 播放结束 -1 播放失败;data.data.position 播放进度百分比 data.data.progress 播放进度
console.log(e);
});
// 耳机
speakListener.addEventListener('headsetListener', function(e) {
// {"data":{"code":0,"msg":"有线耳机已拔出"},"code":0,"msg":"实时播放任务监听"}
// {"data":{"code":11,"msg":"蓝牙耳机已连接"},"code":1,"msg":"耳机状态监听"}
// e.code 0 耳机已拔出或断开 1 耳机已连接
console.log(e);
});
// 通话状态
speakListener.addEventListener('phoneCallListener', function(e) {
// {"data":{"code":0,"msg":"通话结束或未通话"},"code":0,"msg":"通话状态监听"}
// {"data":{"code":1,"msg":"来电响铃"},"code":1,"msg":"通话状态监听"}
// {"data":{"code":2,"msg":"接听电话或拨出电话"},"code":1,"msg":"通话状态监听"}
// e.code 0 通话结束或未通话 1 来电响铃 2 正在接听电话或拨出电话
console.log(e);
});
示例代码
复制代码<template>
<view class="uni-padding-wrap uni-common-mt">
<view>
<textarea maxlength="-1" v-model="words" placeholder="输入要说的内容"></textarea>
</view>
<view>
<text>{{ tips }}</text>
</view>
<view class="uni-title">设置语速</view>
<view>
<slider
v-model="speed"
step="0.5"
min="0.5"
max="3"
@change="setVoiceSpeed"
show-value
/>
</view>
<view class="uni-title">设置音调</view>
<view>
<slider
v-model="pitch"
step="0.5"
min="0.5"
max="3"
@change="setVoicePicth"
show-value
/>
</view>
<view>
<view class="uni-list">
<view class="uni-list-cell">
<view class="uni-list-cell-left">当前选择</view>
<view class="uni-list-cell-db">
<picker @change="bindPickerChange" :value="index" :range="array">
<view class="uni-input">{{ array[index] }}</view>
</picker>
</view>
</view>
</view>
</view>
<view class="padding"></view>
<view>
<radio-group @change="modelChange">
<label
class="uni-list-cell uni-list-cell-pd"
v-for="(item, index) in items"
:key="item.value"
>
<view><radio :value="item.value" :checked="index === playModel" /></view>
<view>{{ item.name }}</view>
</label>
</radio-group>
</view>
<view><button @click="goBatterySetting">跳转到电量保护设置页</button></view>
<view><button @click="goAutoStartSetting">跳转到应用自启动设置页</button></view>
<view><button @click="openNotifySetting">跳转到通知设置页面</button></view>
<view><button @click="checkNotifyEnabled">检查通知权限</button></view>
<view><button @click="init">初始化</button></view>
<view><button @click="getEngines">获取设备已安装的引擎列表</button></view>
<view><button @click="getDefaultEngine">获取当前设备默认引擎</button></view>
<view><button @click="startForeground">创建前台服务</button></view>
<view><button @click="stopForeground">停止前台服务</button></view>
<view><button @click="speak">实时模式播放</button></view>
<view><button @click="stop">停止播放</button></view>
<view><button @click="saveAudioFile">生成音频文件</button></view>
<view><button @click="destorySpeaker">销毁</button></view>
<view><button @click="playerSpeak">音频模式-生成文件并播放</button></view>
<view><button @click="playerPlay">音频模式-播放</button></view>
<view><button @click="playerPause">音频模式-暂停</button></view>
<view><button @click="playerResume">音频模式-继续</button></view>
<view><button @click="playerStop">音频模式-停止播放</button></view>
<view><button @click="getFolderSize">递归获取文件夹大小</button></view>
<view><button @click="getCurrentFolderSize">获取文件夹大小</button></view>
<view><button @click="deleteFolderFile">删除指定目录下的文件及文件夹</button></view>
<view><button @click="deleteFile">删除指定目录下的文件</button></view>
</view>
</template>
<script>
const TTSSpeaker = uni.requireNativePlugin('Karma617-TTSSpeaker');
const speakListener = weex.requireModule('globalEvent');
export default {
data() {
return {
engineList: [],
array: ['请选择引擎'],
index: 0,
words:
'TTS(Text To Speech,文本转语音)是语音合成应用的一种,它将储存于电脑中的文件,如帮助文件或者网页,转换成自然语音输出。',
speed: 2,
pitch: 1,
playModel: 1,
items: [
{
value: 0,
name: '舍弃模式'
},
{
value: 1,
name: '追加模式'
}
],
savePath: '',
tips: '',
engine: ''
};
},
onReady() {
let _this = this;
_this.init();
// TTS实时模式监听播放状态
speakListener.addEventListener('speakListener', function(e) {
// {"data":{"taskid":"666234324563543","code":1,"msg":"播放开始"},"code":0,"msg":"实时播放任务监听"}
// data.code 1 播放开始 2 播放结束 -1 播放失败
console.log(e);
});
// 文字转音频播放监听播放状态
speakListener.addEventListener('mediaListener', function(e) {
// {"data":{"status":1,"data":{"position":97,"progress":6792},"msg":"正在播放"},"code":0,"msg":"音频模式播放任务监听"}
// data.status 1 正在播放 2 播放结束 -1 播放失败;data.data.position 播放进度百分比 data.data.progress 播放进度
console.log(e);
});
// 耳机
speakListener.addEventListener('headsetListener', function(e) {
// {"data":{"code":0,"msg":"有线耳机已拔出"},"code":0,"msg":"实时播放任务监听"}
// {"data":{"code":11,"msg":"蓝牙耳机已连接"},"code":1,"msg":"耳机状态监听"}
// e.code 0 耳机已拔出或断开 1 耳机已连接
console.log(e);
});
},
methods: {
checkNotifyEnabled() {
TTSSpeaker.checkNotifyEnabled();
},
openNotifySetting() {
TTSSpeaker.openNotifySetting();
},
startForeground () {
TTSSpeaker.startForegroundListening();
},
stopForeground () {
TTSSpeaker.stopListening();
},
goBatterySetting () {
TTSSpeaker.goBatterySetting();
},
goAutoStartSetting () {
TTSSpeaker.goAutoStartSetting();
},
bindPickerChange(e) {
this.index = e.detail.value;
this.engine = this.engineList[this.index-1].package_name;
console.log(this.engine);
this.destorySpeaker();
let _this = this;
setTimeout(v => {
_this.init(_this.engine);
}, 500)
},
init(engine) {
console.log(engine);
let _this = this;
_this.array = ['请选择引擎'];
TTSSpeaker.init(
function(result) {
let obj = JSON.parse(result.data)
// 返回设置的语速和音调
_this.pitch = obj.voice_pitch;
_this.speed = obj.voice_speed;
// 返回当前已安装的引擎列表
_this.engineList = JSON.parse(obj.engines);
_this.engineList.forEach(v => {
_this.array.push(v.app_name)
})
},
{
engine: engine || ''
}
);
},
modelChange: function(evt) {
for (let i = 0; i < this.items.length; i++) {
if (this.items[i].value === evt.detail.value) {
this.playModel = i;
break;
}
}
},
speak() {
// 对应参数: 待播放文本,播放模式(1 丢弃之前的播报任务,立即播报本次内容 2 播放完之前的语音任务后才播报本次内容),任务id(用来获取播放状态)
TTSSpeaker.speak(this.words, this.playModel + 1);
},
setVoiceSpeed(e) {
TTSSpeaker.setVoiceSpeed(e.detail.value, function(result) {
uni.showToast({
title: JSON.stringify(result),
icon: 'none'
});
});
},
setVoicePicth(e) {
TTSSpeaker.setVoicePicth(e.detail.value, function(result) {
uni.showToast({
title: JSON.stringify(result),
icon: 'none'
});
});
},
stop() {
TTSSpeaker.stop();
},
destorySpeaker() {
TTSSpeaker.destorySpeaker();
},
getDefaultEngine() {
TTSSpeaker.getDefaultEngine(v => {
uni.showToast({
title: JSON.stringify(v),
icon: 'none'
});
});
},
getEngines() {
// 该方法必须在init初始化之后才能调用。1.1.4版本以后,初始化成功后将一并返回tts引擎列表
this.array = ['请选择引擎'];
TTSSpeaker.getEngines(res => {
this.engineList = res.data;
res.forEach(v => {
this.array.push(v.app_name);
});
uni.showToast({
title: JSON.stringify(v),
icon: 'none'
});
});
},
saveAudioFile() {
// 文字过长时,请加延时,测试8000字,需延时最少2500毫秒。
// 建议将文本分段后再进行合成保存
TTSSpeaker.saveAudioFile(
{
words: this.words,
save_path: '' // 音频文件保存路径,可选,默认保存路径为本应用的cache目录下,例:/xxx/xxx/xxx/audio.wav。
},
function(result) {
// 返回文件目录信息
uni.showToast({
title: JSON.stringify(result),
icon: 'none'
});
}
);
},
playerSpeak() {
let _this = this;
// words待播放文本 , savePath音频文件保存路径,可选,默认保存路径为本应用的cache目录下,例:/xxx/xxx/xxx/audio.wav。
TTSSpeaker.playerSpeak(_this.words, '', res => {
console.log(res);
// {"data":"/storage/emulated/0/Android/data/com.qdapi.ttspeaker/cache/voices/a44fb3b2bffdb007de81935476457587.wav","code":0,"msg":"保存成功"}
_this.savePath = res.data;
});
},
playerPlay() {
TTSSpeaker.playerPlay(this.savePath);
},
playerStop() {
TTSSpeaker.playerStop();
},
playerResume() {
TTSSpeaker.playerResume();
},
playerPause() {
TTSSpeaker.playerPause();
},
getFolderSize() {
TTSSpeaker.getFolderSize('', res => {
// {"data":"217.38KB","code":0,"msg":"获取成功"}
console.log(res);
});
},
getCurrentFolderSize() {
TTSSpeaker.getCurrentFolderSize('', res => {
// {"data":"217.38KB","code":0,"msg":"获取成功"}
console.log(res);
});
},
deleteFolderFile() {
TTSSpeaker.deleteFolderFile('', false, res => {
// {"data":"","code":0,"msg":"删除成功"}
console.log(res);
});
},
deleteFile() {
TTSSpeaker.deleteFile('', res => {
// {"data":"","code":0,"msg":"删除成功"}
console.log(res);
});
}
}
};
</script>
<style>
.padding{
padding: 20px;
}
</style>