vue实现语音合成功能,Android和wap端

概览

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 ,进行小说的语音合成功能(朗读功能)。

如有什么好的建议,希望大佬们能够不吝赐教。拜谢拜谢🙏!!!!

相关推荐
轻口味1 分钟前
命名空间与模块化概述
开发语言·前端·javascript
前端小小王36 分钟前
React Hooks
前端·javascript·react.js
C4rpeDime42 分钟前
自建MD5解密平台-续
android
迷途小码农零零发1 小时前
react中使用ResizeObserver来观察元素的size变化
前端·javascript·react.js
娃哈哈哈哈呀1 小时前
vue中的css深度选择器v-deep 配合!important
前端·css·vue.js
旭东怪2 小时前
EasyPoi 使用$fe:模板语法生成Word动态行
java·前端·word
鲤籽鲲2 小时前
C# Random 随机数 全面解析
android·java·c#
ekskef_sef3 小时前
32岁前端干了8年,是继续做前端开发,还是转其它工作
前端
sunshine6414 小时前
【CSS】实现tag选中对钩样式
前端·css·css3
真滴book理喻4 小时前
Vue(四)
前端·javascript·vue.js