概览
vue项目需要实现小说朗读功能,wap端和Android APP端,wap端能使用的方法在Android端不能使用,需要使用原生Android的方法实现小说朗读功能。
需求分析
1、WAP端实现小说朗读,即语音合成功能实现
2、vue项目打包成Android项目
3、Android端实现小说朗读(语音合成)
4、vue中调用Android原生类
具体实现
1、wap端的不多做讲述,直接上代码
javascript
this.synth = window.speechSynthesis;
// 监听speaking状态变化
this.speakMsg = new SpeechSynthesisUtterance();
this.speakMsg.onend = function(){
console.log("播放结束")
if(document.getElementById(that.intaBook + '')) document.getElementById(that.intaBook + '').style.backgroundColor = ""
that.intaBook = that.intaBook + 1
//最后一段的时候
if(that.intaBook == that.bookContent[0].contentList.length - 2){
console.log("播放结束 最后一段的时候 ")
that.getTTSNextChapter()
if(that.isElementInViewport(document.getElementById('' + that.intaBook))){
console.log("播放结束 最后一段的时候 33333 ")
//如果在当前窗口展示不进行处理
}else{
console.log("播放结束 最后一段的时候 44444 ")
//不在当前窗口展示,进行跳转下一页处理
that.ttsPageFunc(false)
}
}else if(that.intaBook < that.bookContent[0].contentList.length - 2){
console.log("播放结束 2222 ")
if(that.isElementInViewport(document.getElementById('' + that.intaBook))){
console.log("播放结束 33333 ")
//如果在当前窗口展示不进行处理
}else{
console.log("播放结束 44444 ")
//不在当前窗口展示,进行跳转下一页处理
that.ttsPageFunc(false)
}
}else{
console.log("播放结束 播放下一章 ")
if(that.bookCacheContent.length <= 0){
return
}
that.bookContent[0] = that.bookCacheContent[0]
that.intaBook = 0
if(document.getElementById(that.intaBook + '')) document.getElementById(that.intaBook + '').style.backgroundColor = "#DCD1B0"
that.styleObject = '';
that.offsetX = 0;
that.bookCurrentPage++;
that.currentPaging = 1;
that.bookCacheContent = []
}
that.handleSpeak(that.bookContent[0].contentList[that.intaBook])
if(document.getElementById(that.intaBook + '')) document.getElementById(that.intaBook + '').style.backgroundColor = "#DCD1B0"
};
this.handleSpeak(this.bookContent[0].contentList[this.intaBook])
//阅读最后一段落
if(this.intaBook == that.bookContent[0].contentList.length - 2){
console.log("直接播放 最后一段的时候 ")
this.getTTSNextChapter()
}
因为是小说朗读功能,代码中有部分是把小说的内容,根据每一段转成一个字符串,整篇文章放到了一个数组中。
其中的主要方法
javascript
this.speakMsg = new SpeechSynthesisUtterance();
this.speakMsg.onend = function(){
console.log("播放结束")
};
this.speakMsg.text ="需要朗读的内容";
this.speakMsg.lang = 'zh-CN';
this.speakMsg.volume = '1';
this.speakMsg.rate = 1;
this.speakMsg.pitch = 1;
this.synth.speak(this.speakMsg); //这里实现进行语音合成
this.synth.resume();//暂停
this.synth.pause();//暂停之后,该方法为继续播放合成的语音
this.synth.cancel();//关闭停止
2、vue打包成Android项目,参考:vue项目如何打包Android APK(保姆教程)_vue项目打包安卓-CSDN博客
3、重点来了,vue项目如何实现打包的Android APP进行小说朗读
a、首先可以先搞一个Android项目
b、 使用第三方提供的SDK或者API,例如:科大讯飞,百度,阿里等,使用Android系统自带的API :TextToSpeech,TextToSpeech中的API文档:TextToSpeech | Android Developers
c、在AndroidManifest.xml文件中添加权限
java
<!--外存储写权限,构建语法需要用到此权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!--外存储读权限,构建语法需要用到此权限 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
d、Demo中activity中页面布局
javascript
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<EditText
android:id="@+id/et_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="文本输入" />
<Button
android:id="@+id/btn_speech"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="speech" />
</LinearLayout>
e、TextToSpeech介绍,相关的方法
javascript
1、//使用默认的引擎
TextToSpeech(Context context, TextToSpeech.OnInitListener listener)
//使用指定的引擎
TextToSpeech(Context context, TextToSpeech.OnInitListener listener, String engine)
2.textToSpeech.setLanguage():设置播报的语言
3.textToSpeech.speak():播放
4.textToSpeech.setPitch():设置语调,值越大声音越尖锐,越小声音越低沉
5.textToSpeech.setSpeechRate():设置语速,较低的值会减慢语音(0.5是正常语速的一半),更大的值会加速它(2.0是正常语速的两倍)
f、先初始化textToSeepch,再转换(示例用的默认的TTS引擎),activity中具体的代码
Kotlin
package com.yjwxc.ttsproject;
import android.os.Bundle;
import android.speech.tts.TextToSpeech;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.util.Locale;
public class MainActivity extends AppCompatActivity implements TextToSpeech.OnInitListener {
private static final String TAG = "MainActivity";
private TextToSpeech textToSpeech;
private EditText inputEt;
private Button speechBtn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
speechBtn = findViewById(R.id.btn_speech);
inputEt = findViewById(R.id.et_input);
init();
}
private void init() {
textToSpeech = new TextToSpeech(this, this);
//设置语言
int result = textToSpeech.setLanguage(Locale.ENGLISH);
if (result != TextToSpeech.LANG_COUNTRY_AVAILABLE
&& result != TextToSpeech.LANG_AVAILABLE) {
Toast.makeText(MainActivity.this, "TTS暂时不支持这种语音的朗读!",
Toast.LENGTH_SHORT).show();
}
//设置音调,值越大声音越尖(女生),值越小则变成男声,1.0是常规
textToSpeech.setPitch(1.0f);
//设置语速,1.0为正常语速
textToSpeech.setSpeechRate(0.9f);
//speech按钮监听事件
speechBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//播放
textToSpeech.speak(inputEt.getText().toString(),
TextToSpeech.QUEUE_ADD, null);
}
});
}
@Override
public void onInit(int status) {
//初始化成功
if (status == TextToSpeech.SUCCESS) {
Log.d(TAG, "init success");
} else {
Log.d(TAG, "init fail");
}
}
@Override
protected void onDestroy() {
super.onDestroy();
//中断当前话语
textToSpeech.stop();
//释放资源
textToSpeech.shutdown();
}
}
g、面向 Android 11使用文本转语音的应用应先在AndroidManifest.xml声明INTENT_ACTION_TTS_SERVICE
Kotlin
<queries>
<intent>
<action android:name="android.intent.action.TTS_SERVICE" />
</intent>
</queries>
H、可能存在的问题
没有声音或不支持当前设置的语言
需要检查系统是否设置播放引擎,设置--->无障碍 ---> 文本转语音中是否安装了播放引擎;系统默认是应该是Pico TTS,不过这个不支持中文;
需要安装第三方播放引擎
com.svox.pico 系统自带不支持中文语音
com.svox.classic 搜svox搜到的,和上面类似不支持中文
com.google.android.tts 谷歌文字转语音引擎,不支持5.0以下系统,大小17.98M
com.iflytek.speechcloud 科大讯飞语音引擎3.0,支持4.0以上系统,大小27.27M
com.iflytek.speechsuite 新版科大讯飞语音引擎,2018年开始新版手机一般会内置,如oppo、vivo、华为
com.baidu.duersdk.opensdk 度秘语音引擎3.0 不支持5.0以下系统,大小11.95M
com.iflytek.tts 科大讯飞语音合成,较老,不支持7.0以上系统,大小9M
现在的Android手机基本上都已经自带了讯飞语音引擎,可以进行中文的语音合成功能。
可以下载Demo进行测试:https://download.csdn.net/download/ahualong1/89921075
4、如何在vue中调用Android中的方法
先上代码
Kotlin
package com.yjwxc.yj;
import android.app.Activity;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.speech.tts.TextToSpeech;
import android.speech.tts.UtteranceProgressListener;
import android.util.Log;
import android.webkit.JavascriptInterface;
import android.webkit.WebView;
import android.widget.Toast;
import java.util.HashMap;
import java.util.Locale;
public class JsJavaBridge {
private TextToSpeech tts;
private Activity activity;
private WebView webView;
private boolean isPlaying = false;
private boolean isPaused = false;
private String[] bookDataList = new String[0];
private int inta = 0;
public JsJavaBridge() {
}
/**
* 初始化tts
* @return
*/
public void androidTtsInit(){
Log.e("TEST","初始化 方法 null == tts");
tts = new TextToSpeech(this.activity, new TextToSpeech.OnInitListener() {
@Override
public void onInit(int status) {
if(status == tts.SUCCESS){
int result = tts.setLanguage(Locale.CHINA);
// tts.setOnUtteranceProgressListener(new ClearUtteranceProgressListener());
if(result != TextToSpeech.LANG_COUNTRY_AVAILABLE && result != TextToSpeech.LANG_AVAILABLE){
showTip("TTS暂时不支持这种语言的朗读");
Log.e("TEST","TTS暂时不支持这种语言的朗读");
}
}
Log.e("TEST","status " + status);
Log.e("TEST","tts.SUCCESS " + tts.SUCCESS);
}
});
tts.setOnUtteranceProgressListener(new ClearUtteranceProgressListener());
// if(null == tts){
//
// }else{
// Log.e("TEST","初始化 方法 null != tts");
// }
}
public JsJavaBridge(MainActivity mainActivity, WebView webView) {
this.activity = mainActivity;
this.webView = webView;
}
@JavascriptInterface
public void onFinishActivity() {
activity.finish();
}
/**
* 开始播放内容
* @param stringData
*/
@JavascriptInterface
public void speakStartPlay(String stringData){
Log.d("TEST","打印传递过来的数据 " + stringData);
tts = new TextToSpeech(this.activity, new TextToSpeech.OnInitListener() {
@Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
// 设置语言
int result = tts.setLanguage(Locale.SIMPLIFIED_CHINESE); // 或者其他所需语言
if (result != TextToSpeech.LANG_COUNTRY_AVAILABLE || result != TextToSpeech.LANG_AVAILABLE) {
showTip("不支持当前语言");
return;
}
// 开始朗读文本
String text = stringData; // 获取小说章节的内容
tts.speak(text, TextToSpeech.QUEUE_ADD, null);
} else {
showTip("初始化失败");
}
}
});
// if (tts != null) {
// tts.speak(stringData,TextToSpeech.QUEUE_ADD,null);
// }else{
// this.showTip("初始化失败");
// Log.e("TEST","初始化失败 传递的内容 " + stringData);
// }
}
/**
* 继续播放
*/
@JavascriptInterface
public void continueSpeakPlay(){
if (tts != null) {
// 对于旧版本的Android,使用isSpeaking检查并继续播放
if (!tts.isSpeaking()) {
HashMap<String, String> params = new HashMap<>();
params.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "resume");
tts.speak("", TextToSpeech.QUEUE_ADD, params);
}
}
}
/**
* 暂停播放
* @return
*/
@JavascriptInterface
public void pauseSpeakPlay(){
Log.e("TEST","pauseSpeakPlay 暂停播放");
if (isPlaying && !isPaused) {
Log.e("TEST","isPlaying && !isPaused 暂停播放");
tts.stop();
isPaused = true;
}
}
/**
* 停止播放
* @return
*/
@JavascriptInterface
public void stopSpeakPlay(){
Log.e("TEST","stopSpeakPlay 停止播放");
if (tts != null) {
Log.e("TEST","tts != null 停止播放");
tts.stop();
tts.shutdown();
}
}
private void showTip(final String str) {
Toast.makeText(this.activity, str, Toast.LENGTH_SHORT).show();
}
private class ClearUtteranceProgressListener extends UtteranceProgressListener {
@Override
public void onStart(String s) {
Log.e("TEST","方法 onStart " + s);
isPlaying = true;
isPaused = false;
}
@Override
public void onDone(String s) {
Log.e("TEST","方法 onDone " + s);
isPlaying = false;
}
@Override
public void onError(String s) {
Log.e("TEST","方法 onError " + s);
isPlaying = false;
}
};
}
@JavascriptInterface
是Android JavaScript Interface库(如DroidGap/Cordova)提供的一种注解,它允许Java开发者创建JavaScript可以访问的接口。当一个Java方法被这个注解修饰后,JavaScript可以在运行时通过WebView调用该方法,实现Java与JavaScript之间的交互。这种方式常用于构建混合应用(Hybrid App),即结合了原生组件和Web内容的应用。
Kotlin
/**
* 停止播放
* @return
*/
@JavascriptInterface
public void stopSpeakPlay(){
Log.e("TEST","stopSpeakPlay 停止播放");
if (tts != null) {
Log.e("TEST","tts != null 停止播放");
tts.stop();
tts.shutdown();
}
}
上面该方法是Android中停止播放的方法,在vue中如何调用,如下:
javascript
stopFn() {
console.log("打印stop")
if(typeof $Android !== 'undefined'){
$Android.stopSpeakPlay();
}else{
if(this.synth){
// this.synth.pause();
this.synth.cancel();
this.synth = null;
this.speakMsg = null;
this.isSpeaking = "STOP";
var that = this
if(document.getElementById(that.intaBook + '')) document.getElementById(that.intaBook + '').style.backgroundColor = ""
this.intaBook = 0
}
}
this.musice_box = false;
},
$Android.stopSpeakPlay(); 即为调用的Android中定义的方法。
到这里结合上面4个部分的具体实现内容,即可实现vue项目打包成wap和AndroidAPP ,进行小说的语音合成功能(朗读功能)。
如有什么好的建议,希望大佬们能够不吝赐教。拜谢拜谢🙏!!!!