Beeware生成安卓apk取得系统tts语音朗读例子

我在写一些安卓程序,用的是beeware的toga,最近对文件权限等有所突破,为此,我想写一个简单的程序获取系统的tts语音朗读功能,因为我发现termux可以用系统的tts,我就认为java可以调用系统tts功能,于是问了deepseek。

源代码app.py

python 复制代码
import toga
from toga.style import Pack
from toga.style.pack import COLUMN, ROW
import threading

class SystemTTSApp(toga.App):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.tts_engine = None
        self.tts_ready = False
    
    def startup(self):
        # 创建主容器
        main_box = toga.Box(style=Pack(direction=COLUMN, padding=20, flex=1))
        
        # 标题
        title_label = toga.Label(
            '语音朗读程序',
            style=Pack(padding=(0, 0, 10, 0), font_size=20, font_weight='bold')
        )
        
        # 创建输入框
        self.input_text = toga.TextInput(
            placeholder='请输入要朗读的文字(中英文均可)...',
            style=Pack(flex=0, padding=5)
        )
        
        # 创建测试按钮
        test_button = toga.Button(
            '测试TTS',
            on_press=self.test_tts,
            style=Pack(flex=1, padding=10, background_color='#4CAF50', color='white')
        )
        
        # 创建按钮
        button_box = toga.Box(style=Pack(direction=ROW, padding=10))
        
        display_button = toga.Button(
            '显示文字',
            on_press=self.display_text,
            style=Pack(flex=1, padding=10)
        )
        
        speak_button = toga.Button(
            '朗读文字',
            on_press=self.speak_text,
            style=Pack(flex=1, padding=10)
        )
        
        button_box.add(display_button)
        button_box.add(speak_button)
        
        # 显示区域 - 使用MultilineTextInput替代Label,支持自动换行
        self.output_display = toga.MultilineTextInput(
            readonly=True,
            placeholder='这里将显示输入的文字',
            style=Pack(flex=1, padding=10, font_size=14, background_color='#f5f5f5')
        )
        
        # 状态显示区域 - 同样使用MultilineTextInput,支持自动换行
        self.status_display = toga.MultilineTextInput(
            readonly=True,
            placeholder='状态信息将在这里显示',
            style=Pack(flex=0, padding=10, font_size=12, background_color='#e8f4f8', height=100)
        )
        
        # 添加到主容器
        main_box.add(title_label)
        main_box.add(self.input_text)
        main_box.add(test_button)
        main_box.add(button_box)
        main_box.add(self.output_display)
        main_box.add(self.status_display)
        
        # 创建主窗口
        self.main_window = toga.MainWindow(title=self.formal_name, size=(400, 600))
        self.main_window.content = main_box
        self.main_window.show()
        
        # 初始化TTS
        self.init_tts()
    
    def init_tts(self):
        """初始化系统TTS引擎"""
        self.update_status("正在初始化语音引擎...")
        threading.Thread(target=self._init_tts_thread, daemon=True).start()
    
    def _init_tts_thread(self):
        """在新线程中初始化TTS"""
        try:
            # 导入必要的Java类
            from rubicon.java import JavaClass
            
            # 获取TTS类
            TextToSpeech = JavaClass('android.speech.tts.TextToSpeech')
            Locale = JavaClass('java.util.Locale')
            Context = JavaClass('android.content.Context')
            
            # 获取当前Activity
            activity = self.main_window._impl.app.native
            
            # 创建TTS引擎
            self.tts_engine = TextToSpeech(activity, None)
            
            # 检查初始化状态
            import time
            time.sleep(1)  # 等待初始化完成
            
            # 设置语言
            result = self.tts_engine.setLanguage(Locale.CHINESE)
            
            if result == TextToSpeech.LANG_MISSING_DATA:
                self.update_status("❌ TTS初始化失败:缺少中文语音数据\n请安装中文TTS语音包")
                self.tts_ready = False
            elif result == TextToSpeech.LANG_NOT_SUPPORTED:
                self.update_status("❌ TTS初始化失败:不支持中文\n尝试使用默认语言")
                self.tts_engine.setLanguage(Locale.getDefault())
                self.tts_ready = True
                self.update_status("✅ TTS已就绪(使用默认语言)")
            elif result == TextToSpeech.SUCCESS:
                self.update_status("✅ TTS已就绪(支持中文)")
                self.tts_ready = True
            else:
                self.update_status(f"❌ TTS初始化失败:未知错误代码 {result}")
                self.tts_ready = False
            
            # 检查TTS引擎详细信息
            engines = self.tts_engine.getEngines()
            default_engine = self.tts_engine.getDefaultEngine()
            self.update_status(f"可用引擎: {engines}\n默认引擎: {default_engine}")
            
        except Exception as e:
            import traceback
            error_details = traceback.format_exc()
            self.update_status(f"""
❌ TTS初始化失败:

错误信息:
{str(e)}

详细错误:
{error_details}

可能的原因:
1. 设备没有安装TTS引擎
2. 应用缺少TTS权限
3. 不支持当前Android版本

建议操作:
1. 安装Google Text-to-Speech引擎
2. 在系统设置中检查TTS配置
3. 重启设备后重试
""")
            self.tts_ready = False
    
    def test_tts(self, widget):
        """测试TTS功能"""
        self.update_status("开始测试TTS功能...")
        
        if not self.tts_ready or not self.tts_engine:
            self.update_status("TTS引擎未初始化,无法测试")
            return
        
        # 测试朗读
        test_text = "您好,这是一个测试语音。Hello, this is a test."
        
        # 在新线程中测试
        threading.Thread(target=self._test_tts_thread, args=(test_text,), daemon=True).start()
    
    def _test_tts_thread(self, text):
        """在新线程中测试TTS"""
        try:
            from rubicon.java import JavaClass
            TextToSpeech = JavaClass('android.speech.tts.TextToSpeech')
            
            # 更新状态
            self.update_status(f"🔊 测试朗读: {text}")
            
            # 使用不同的参数测试
            test_params = [
                (TextToSpeech.QUEUE_FLUSH, None, "test_1"),
                (TextToSpeech.QUEUE_ADD, None, "test_2"),
            ]
            
            # 测试不同的语音模式和设置
            self.tts_engine.setPitch(1.0)  # 正常音调
            self.tts_engine.setSpeechRate(1.0)  # 正常语速
            
            # 朗读测试文字
            result = self.tts_engine.speak(
                text,
                TextToSpeech.QUEUE_FLUSH,
                None,
                "tts_test"
            )
            
            self.update_status(f"朗读结果代码: {result}")
            
            if result == TextToSpeech.SUCCESS:
                self.update_status("✅ 测试成功:朗读已开始")
                
                # 等待朗读完成
                import time
                time.sleep(3)  # 等待3秒让朗读完成
                
                # 检查是否正在朗读
                is_speaking = self.tts_engine.isSpeaking()
                self.update_status(f"是否正在朗读: {is_speaking}")
                
                if is_speaking:
                    self.update_status("✅ TTS工作正常,正在播放声音")
                else:
                    self.update_status("⚠️ TTS没有播放声音,但返回了成功代码")
            else:
                self.update_status("❌ 测试失败:无法开始朗读")
                
        except Exception as e:
            self.update_status(f"❌ 测试失败: {str(e)}")
    
    def update_status(self, message):
        """更新状态显示"""
        self.main_window.app._impl.loop.call_soon_threadsafe(
            lambda: setattr(self.status_display, 'value', message)
        )
    
    def update_output(self, message):
        """更新输出显示"""
        self.main_window.app._impl.loop.call_soon_threadsafe(
            lambda: setattr(self.output_display, 'value', message)
        )
    
    def display_text(self, widget):
        """显示文字"""
        input_text = self.input_text.value
        if input_text:
            self.update_output(f"📝 输入的内容是:\n\n{input_text}")
            self.update_status("文字已显示")
        else:
            self.update_output("⚠️ 请输入一些文字...")
            self.update_status("输入框为空")
    
    def speak_text(self, widget):
        """朗读文字"""
        input_text = self.input_text.value
        if not input_text:
            self.update_status("请输入要朗读的文字")
            return
        
        if not self.tts_ready or not self.tts_engine:
            self.update_status("TTS引擎未就绪,请先点击'测试TTS'按钮")
            return
        
        # 在新线程中朗读,避免阻塞UI
        threading.Thread(target=self._speak_thread, args=(input_text,), daemon=True).start()
    
    def _speak_thread(self, text):
        """在新线程中执行朗读"""
        try:
            from rubicon.java import JavaClass
            TextToSpeech = JavaClass('android.speech.tts.TextToSpeech')
            
            # 更新状态
            self.update_status("🔊 正在朗读...")
            self.update_output(f"🔊 正在朗读:\n\n{text}")
            
            # 设置参数
            self.tts_engine.setPitch(1.0)  # 正常音调
            self.tts_engine.setSpeechRate(0.9)  # 稍微慢一点,更容易听清
            
            # 朗读文字
            result = self.tts_engine.speak(
                text,
                TextToSpeech.QUEUE_FLUSH,
                None,
                f"tts_{hash(text)}"  # 唯一的utterance ID
            )
            
            self.update_status(f"朗读调用结果代码: {result}")
            
            if result == TextToSpeech.SUCCESS:
                self.update_status("✅ 朗读已开始")
                
                # 等待朗读完成(简单延时)
                import time
                estimated_time = min(len(text) * 0.15, 10.0)  # 最多等待10秒
                time.sleep(estimated_time)
                
                self.update_status("✅ 朗读应该已完成")
            else:
                self.update_status(f"❌ 无法开始朗读,错误代码: {result}")
            
        except Exception as e:
            error_msg = str(e)
            self.update_status(f"❌ 朗读出错:\n\n{error_msg}")

def main():
    return SystemTTSApp('语音朗读', 'com.example.ttsapp')

if __name__ == '__main__':
    app = main()
    app.main_loop()

这个程序好像不用怎么设置就可以在Android12上使用。在Android15上,发现不能用。为此再一直问deepseek,但他的回答越来越复杂,所以我还是最终用这个py文件。

在AndroidManifest.xml 加上相关内容:

XML 复制代码
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.ttsdiagnostic">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    
    <!-- TTS相关权限 -->
    <uses-permission android:name="android.permission.BIND_TTS_SERVICE" />
    
    <application
        android:allowBackup="true"
        android:icon="@mipmap/icon"
        android:label="@string/app_name"
        android:theme="@style/AppTheme">
        
        <activity
            android:name=".MainActivity"
            android:configChanges="orientation|screenSize|keyboardHidden"
            android:label="@string/app_name"
            android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        
        <!-- TTS引擎查询 -->
        <queries>
            <intent>
                <action android:name="android.intent.action.TTS_SERVICE" />
            </intent>
        </queries>
        
    </application>

</manifest>

pyproject.toml文件加上:requires = [

"rubicon-java",

]

我感觉可以不加。

安卓系统没有文字转语音,该怎么进行tts转语音

下载需要的应用

链接:https://pan.baidu.com/s/1zb3EUNRAaG_6rfiE8gtVHg

提取码:y68z

相关推荐
zhangphil3 小时前
Android图像显示,CPU的Skia与GPU的Vulkan高性能渲染系统
android
故事不长丨3 小时前
安卓相机开发:Camera、Camera2与CameraX的使用对比及选型指南
android·相机·camera·camerax·camera2·移动设备·相机开发
_李小白4 小时前
【Android 美颜相机】第七天:GLTextureView 解析
android·数码相机
honortech4 小时前
Android studio中配置gradle和对应的AGP版本
android·ide·android studio
廋到被风吹走4 小时前
【数据库】【MySQL】事务隔离深度解析:MVCC 实现与幻读解决机制
android·数据库·mysql
AC赳赳老秦4 小时前
技术文档合著:DeepSeek辅助多人协作文档的风格统一与内容补全
android·大数据·人工智能·微服务·golang·自动化·deepseek
赛恩斯4 小时前
安卓构建工具D8和R8的区别
android
—Qeyser4 小时前
Flutter CustomScrollView 自定义滚动视图 - 完全指南
android·flutter·ios
鸣弦artha5 小时前
Flutter 框架跨平台鸿蒙开发 —— Image Widget 图片处理:圆角、裁剪、阴影
android·flutter·harmonyos