欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net


一、flutter_tts 库简介

flutter_tts 是一个功能强大的文字转语音(TTS)插件,支持将文本转换为语音输出。无论是无障碍应用、语音播报、导航提示还是教育类应用,flutter_tts 都能提供高质量的语音合成能力。

flutter_tts 核心特点

特点 说明
文字转语音 将文本转换为自然语音输出
多语言支持 支持中文、英文等多种语言
语速控制 可调节语音播放速度
音调控制 可调节语音音调高低
音量控制 可调节语音音量大小
暂停继续 支持暂停和继续播放
进度回调 实时获取语音播放进度
语音选择 支持选择不同语音引擎和声音
跨平台兼容 支持 Android、iOS、Web、OpenHarmony

平台功能支持对比

功能 Android iOS Web OpenHarmony
文字转语音 ✔️ ✔️ ✔️ ✔️
多语言支持 ✔️ ✔️ ✔️ ✔️
语速控制 ✔️ ✔️ ✔️ ✔️
音调控制 ✔️ ✔️ ✔️ ✔️
音量控制 ✔️ ✔️ ✔️ ✔️
暂停继续 ✔️ ✔️ ✔️ ✔️
进度回调 ✔️ ✔️ ✔️ ✔️
语音选择 ✔️ ✔️ ✔️
合成到文件 ✔️ ✔️

使用场景

  • 无障碍应用(屏幕阅读器)
  • 导航语音提示
  • 教育类应用(单词朗读)
  • 新闻/文章语音播报
  • 客服语音助手

二、OpenHarmony 适配版本

2.1 环境说明

组件 版本
Flutter 3.27.5
HarmonyOS 6.0
flutter_tts 4.0.2 (OpenHarmony 适配版本)

2.2 引入方式

pubspec.yaml 文件中添加以下依赖配置:

dependencies:
  flutter_tts:
    git:
      url: https://atomgit.com/openharmony-sig/flutter_tts.git
      ref: master

三、核心 API 讲解

3.1 FlutterTts 类

FlutterTts 是文字转语音的核心类,提供语音合成、语音控制、语音设置等功能。

构造函数
final flutterTts = FlutterTts();

3.2 语音控制方法

speak - 朗读文本
Future<dynamic> speak(String text)

参数说明:

参数 类型 必填 说明
text String 要朗读的文本

说明: 开始朗读指定文本,如果正在朗读其他文本,会先停止当前朗读。

使用示例:

final flutterTts = FlutterTts();
await flutterTts.speak('欢迎使用语音播报助手');
stop - 停止朗读
Future<dynamic> stop()

说明: 立即停止当前朗读,清除朗读队列。

使用示例:

await flutterTts.stop();
pause - 暂停朗读
Future<dynamic> pause()

说明: 暂停当前朗读,可以通过继续操作恢复。

使用示例:

await flutterTts.pause();
awaitSpeakCompletion - 等待朗读完成
Future<dynamic> awaitSpeakCompletion(bool awaitCompletion)

参数说明:

参数 类型 必填 说明
awaitCompletion bool 是否等待朗读完成返回 Future

说明: 设置 speak 方法是否返回 Future,等待朗读完成。

使用示例:

await flutterTts.awaitSpeakCompletion(true);
await flutterTts.speak('这是一段文本');
print('朗读完成');

3.3 语音设置方法

setLanguage - 设置语言
Future<dynamic> setLanguage(String language)

参数说明:

参数 类型 必填 说明
language String 语言代码,如 zh-CN

常用语言代码:

语言代码 说明
zh-CN 中文(简体)
zh-TW 中文(繁体)
en-US 英语(美国)
en-GB 英语(英国)
ja-JP 日语
ko-KR 韩语
fr-FR 法语
de-DE 德语

使用示例:

await flutterTts.setLanguage('zh-CN');
setSpeechRate - 设置语速
Future<dynamic> setSpeechRate(double rate)

参数说明:

参数 类型 必填 说明
rate double 语速,范围 0.0 - 1.0

语速范围:

说明
0.0 最慢
0.5 正常
1.0 最快

使用示例:

await flutterTts.setSpeechRate(0.5);
setVolume - 设置音量
Future<dynamic> setVolume(double volume)

参数说明:

参数 类型 必填 说明
volume double 音量,范围 0.0 - 1.0

音量范围:

说明
0.0 静音
0.5 中等
1.0 最大

使用示例:

await flutterTts.setVolume(0.8);
setPitch - 设置音调
Future<dynamic> setPitch(double pitch)

参数说明:

参数 类型 必填 说明
pitch double 音调,范围 0.5 - 2.0

音调范围:

说明
0.5 最低
1.0 正常
2.0 最高

使用示例:

await flutterTts.setPitch(1.0);
setVoice - 设置特定语音
Future<dynamic> setVoice(Map<String, String> voice)

参数说明:

参数 类型 必填 说明
voice Map<String, String> 语音配置 Map

使用示例:

await flutterTts.setVoice({'name': 'zh-CN', 'locale': 'zh-CN'});
clearVoice - 清除语音设置
Future<dynamic> clearVoice()

说明: 重置为默认语音设置。

使用示例:

await flutterTts.clearVoice();

3.4 查询方法

getLanguages - 获取支持的语言列表
Future<dynamic> get getLanguages

返回值: 语言代码列表,如 ['zh-CN', 'en-US', 'ja-JP']

使用示例:

final languages = await flutterTts.getLanguages;
print('支持的语言: $languages');
getVoices - 获取可用语音列表
Future<dynamic> get getVoices

返回值: 语音列表,每个语音包含 name、locale 等信息。

使用示例:

final voices = await flutterTts.getVoices;
for (var voice in voices) {
  print('语音: ${voice['name']}, 语言: ${voice['locale']}');
}
isLanguageAvailable - 检查语言是否可用
Future<dynamic> isLanguageAvailable(String language)

参数说明:

参数 类型 必填 说明
language String 语言代码

返回值: truefalse

使用示例:

final isAvailable = await flutterTts.isLanguageAvailable('zh-CN');
if (isAvailable) {
  print('中文可用');
}
getSpeechRateValidRange - 获取语速有效范围
Future<SpeechRateValidRange> get getSpeechRateValidRange

返回值: SpeechRateValidRange 对象。

SpeechRateValidRange 属性:

属性 类型 说明
min double 最小语速
normal double 正常语速
max double 最大语速
platform TextToSpeechPlatform 平台

使用示例:

final range = await flutterTts.getSpeechRateValidRange;
print('语速范围: ${range.min} - ${range.max}');

3.5 回调设置

setStartHandler - 设置开始回调
void setStartHandler(VoidCallback callback)

使用示例:

flutterTts.setStartHandler(() {
  print('开始朗读');
});
setCompletionHandler - 设置完成回调
void setCompletionHandler(VoidCallback callback)

使用示例:

flutterTts.setCompletionHandler(() {
  print('朗读完成');
});
setPauseHandler - 设置暂停回调
void setPauseHandler(VoidCallback callback)

使用示例:

flutterTts.setPauseHandler(() {
  print('已暂停');
});
setContinueHandler - 设置继续回调
void setContinueHandler(VoidCallback callback)

使用示例:

flutterTts.setContinueHandler(() {
  print('继续朗读');
});
setProgressHandler - 设置进度回调
void setProgressHandler(ProgressHandler callback)

ProgressHandler 类型定义:

typedef ProgressHandler = void Function(
    String text, int start, int end, String word);

参数说明:

参数 类型 说明
text String 完整文本
start int 当前开始位置
end int 当前结束位置
word String 当前朗读单词

使用示例:

flutterTts.setProgressHandler((text, start, end, word) {
  print('当前朗读: $word');
  print('进度: $start - $end');
});
setErrorHandler - 设置错误回调
void setErrorHandler(ErrorHandler handler)

ErrorHandler 类型定义:

typedef ErrorHandler = void Function(dynamic message);

使用示例:

flutterTts.setErrorHandler((msg) {
  print('错误: $msg');
});

四、应用级别完整代码:语音播报助手

在这里插入图片描述

import 'package:flutter/material.dart';
import 'package:flutter_tts/flutter_tts.dart';

void main() {
  runApp(const TtsApp());
}

class TtsApp extends StatelessWidget {
  const TtsApp({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '语音播报助手',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: const Color(0xFF673AB7)),
        useMaterial3: true,
      ),
      home: const TtsHomePage(),
    );
  }
}

class TtsHomePage extends StatelessWidget {
  const TtsHomePage({super.key});

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('语音播报助手'),
        backgroundColor: const Color(0xFF673AB7),
        foregroundColor: Colors.white,
        elevation: 0,
      ),
      body: const TtsMainPage(),
    );
  }
}

class TtsMainPage extends StatefulWidget {
  const TtsMainPage({super.key});

  
  State<TtsMainPage> createState() => _TtsMainPageState();
}

class _TtsMainPageState extends State<TtsMainPage> {
  late FlutterTts _flutterTts;
  final TextEditingController _textController = TextEditingController();
  bool _isSpeaking = false;
  bool _isPaused = false;
  double _speechRate = 0.5;
  double _pitch = 1.0;
  double _volume = 1.0;
  String _selectedLanguage = 'zh-CN';
  String _currentStatus = '就绪';
  final List<String> _history = [];

  final List<Map<String, String>> _languages = [
    {'code': 'zh-CN', 'name': '中文(简体)'},
    {'code': 'zh-TW', 'name': '中文(繁体)'},
    {'code': 'en-US', 'name': '英语(美国)'},
    {'code': 'en-GB', 'name': '英语(英国)'},
    {'code': 'ja-JP', 'name': '日语'},
    {'code': 'ko-KR', 'name': '韩语'},
    {'code': 'fr-FR', 'name': '法语'},
    {'code': 'de-DE', 'name': '德语'},
  ];

  final List<String> _presetTexts = [
    '欢迎使用语音播报助手,这是一个文字转语音的应用示例。',
    'Hello, welcome to the text-to-speech application demo.',
    '今天天气真不错,适合出去走走。',
    'The quick brown fox jumps over the lazy dog.',
    '开源鸿蒙是一个面向全场景的分布式操作系统。',
  ];

  
  void initState() {
    super.initState();
    _initTts();
  }

  Future<void> _initTts() async {
    _flutterTts = FlutterTts();

    _flutterTts.setStartHandler(() {
      if (mounted) {
        setState(() {
          _isSpeaking = true;
          _isPaused = false;
          _currentStatus = '正在朗读...';
        });
      }
    });

    _flutterTts.setCompletionHandler(() {
      if (mounted) {
        setState(() {
          _isSpeaking = false;
          _isPaused = false;
          _currentStatus = '朗读完成';
        });
        _addHistory(_textController.text);
      }
    });

    _flutterTts.setPauseHandler(() {
      if (mounted) {
        setState(() {
          _isPaused = true;
          _currentStatus = '已暂停';
        });
      }
    });

    _flutterTts.setContinueHandler(() {
      if (mounted) {
        setState(() {
          _isPaused = false;
          _currentStatus = '正在朗读...';
        });
      }
    });

    _flutterTts.setErrorHandler((msg) {
      if (mounted) {
        setState(() {
          _isSpeaking = false;
          _isPaused = false;
          _currentStatus = '错误: $msg';
        });
      }
    });

    await _flutterTts.setLanguage(_selectedLanguage);
    await _flutterTts.setSpeechRate(_speechRate);
    await _flutterTts.setVolume(_volume);
    await _flutterTts.setPitch(_pitch);
  }

  void _addHistory(String text) {
    if (text.isNotEmpty && mounted) {
      setState(() {
        _history.insert(0, text);
        if (_history.length > 10) {
          _history.removeLast();
        }
      });
    }
  }

  
  void dispose() {
    _flutterTts.stop();
    _textController.dispose();
    super.dispose();
  }

  Future<void> _speak() async {
    if (_textController.text.isEmpty) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('请输入要朗读的文本')),
      );
      return;
    }

    setState(() {
      _currentStatus = '准备朗读...';
    });

    await _flutterTts.speak(_textController.text);
  }

  Future<void> _stop() async {
    await _flutterTts.stop();
    if (mounted) {
      setState(() {
        _isSpeaking = false;
        _isPaused = false;
        _currentStatus = '已停止';
      });
    }
  }

  Future<void> _pause() async {
    await _flutterTts.pause();
  }

  Future<void> _setLanguage(String language) async {
    await _flutterTts.setLanguage(language);
    if (mounted) {
      setState(() {
        _selectedLanguage = language;
      });
    }
  }

  Future<void> _setSpeechRate(double rate) async {
    await _flutterTts.setSpeechRate(rate);
    if (mounted) {
      setState(() {
        _speechRate = rate;
      });
    }
  }

  Future<void> _setPitch(double pitch) async {
    await _flutterTts.setPitch(pitch);
    if (mounted) {
      setState(() {
        _pitch = pitch;
      });
    }
  }

  Future<void> _setVolume(double volume) async {
    await _flutterTts.setVolume(volume);
    if (mounted) {
      setState(() {
        _volume = volume;
      });
    }
  }

  
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      padding: const EdgeInsets.all(16),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          _buildStatusCard(),
          const SizedBox(height: 16),
          _buildTextInputCard(),
          const SizedBox(height: 16),
          _buildControlButtons(),
          const SizedBox(height: 16),
          _buildSettingsCard(),
          const SizedBox(height: 16),
          _buildPresetTextsCard(),
          const SizedBox(height: 16),
          if (_history.isNotEmpty) _buildHistoryCard(),
        ],
      ),
    );
  }

  Widget _buildStatusCard() {
    return Card(
      elevation: 2,
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Row(
          children: [
            Icon(
              _isSpeaking
                  ? (_isPaused ? Icons.pause_circle : Icons.volume_up)
                  : Icons.volume_off,
              color: _isSpeaking
                  ? (_isPaused ? Colors.orange : const Color(0xFF673AB7))
                  : Colors.grey,
              size: 32,
            ),
            const SizedBox(width: 16),
            Expanded(
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  const Text(
                    '当前状态',
                    style: TextStyle(
                      fontSize: 14,
                      color: Colors.grey,
                    ),
                  ),
                  Text(
                    _currentStatus,
                    style: const TextStyle(
                      fontSize: 16,
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildTextInputCard() {
    return Card(
      elevation: 2,
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const Text(
              '输入文本',
              style: TextStyle(
                fontSize: 16,
                fontWeight: FontWeight.bold,
              ),
            ),
            const SizedBox(height: 12),
            TextField(
              controller: _textController,
              maxLines: 4,
              decoration: InputDecoration(
                hintText: '请输入要朗读的文本...',
                border: OutlineInputBorder(
                  borderRadius: BorderRadius.circular(8),
                ),
                contentPadding: const EdgeInsets.all(12),
              ),
            ),
            const SizedBox(height: 12),
            Row(
              children: [
                Expanded(
                  child: DropdownButtonFormField<String>(
                    value: _selectedLanguage,
                    decoration: const InputDecoration(
                      labelText: '语言',
                      border: OutlineInputBorder(),
                      contentPadding: EdgeInsets.symmetric(
                        horizontal: 12,
                        vertical: 8,
                      ),
                    ),
                    items: _languages.map((lang) {
                      return DropdownMenuItem<String>(
                        value: lang['code'],
                        child: Text(lang['name']!),
                      );
                    }).toList(),
                    onChanged: (value) {
                      if (value != null) {
                        _setLanguage(value);
                      }
                    },
                  ),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildControlButtons() {
    return Card(
      elevation: 2,
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: [
            _buildControlButton(
              '朗读',
              Icons.play_arrow,
              const Color(0xFF673AB7),
              _speak,
              _isSpeaking && !_isPaused,
            ),
            _buildControlButton(
              '暂停',
              Icons.pause,
              Colors.orange,
              _pause,
              !_isSpeaking || _isPaused,
            ),
            _buildControlButton(
              '继续',
              Icons.skip_next,
              Colors.blue,
              _speak,
              !_isPaused,
            ),
            _buildControlButton(
              '停止',
              Icons.stop,
              Colors.red,
              _stop,
              !_isSpeaking,
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildControlButton(
    String label,
    IconData icon,
    Color color,
    VoidCallback onPressed,
    bool disabled,
  ) {
    return Column(
      children: [
        ElevatedButton(
          onPressed: disabled ? null : onPressed,
          style: ElevatedButton.styleFrom(
            backgroundColor: disabled ? Colors.grey[300] : color,
            foregroundColor: Colors.white,
            shape: RoundedRectangleBorder(
              borderRadius: BorderRadius.circular(12),
            ),
            padding: const EdgeInsets.all(16),
          ),
          child: Icon(icon, size: 28),
        ),
        const SizedBox(height: 4),
        Text(
          label,
          style: TextStyle(
            fontSize: 12,
            color: disabled ? Colors.grey : Colors.black87,
          ),
        ),
      ],
    );
  }

  Widget _buildSettingsCard() {
    return Card(
      elevation: 2,
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const Text(
              '语音设置',
              style: TextStyle(
                fontSize: 16,
                fontWeight: FontWeight.bold,
              ),
            ),
            const SizedBox(height: 16),
            _buildSliderRow(
              '语速',
              _speechRate,
              0.0,
              1.0,
              (value) => _setSpeechRate(value),
              '${(_speechRate * 100).toInt()}%',
            ),
            const Divider(),
            _buildSliderRow(
              '音调',
              _pitch,
              0.5,
              2.0,
              (value) => _setPitch(value),
              _pitch.toStringAsFixed(1),
            ),
            const Divider(),
            _buildSliderRow(
              '音量',
              _volume,
              0.0,
              1.0,
              (value) => _setVolume(value),
              '${(_volume * 100).toInt()}%',
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildSliderRow(
    String label,
    double value,
    double min,
    double max,
    ValueChanged<double> onChanged,
    String displayValue,
  ) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            Text(label, style: const TextStyle(fontSize: 14)),
            Text(
              displayValue,
              style: TextStyle(
                fontSize: 14,
                color: Colors.grey[600],
                fontWeight: FontWeight.w500,
              ),
            ),
          ],
        ),
        Slider(
          value: value,
          min: min,
          max: max,
          divisions: 10,
          onChanged: onChanged,
        ),
      ],
    );
  }

  Widget _buildPresetTextsCard() {
    return Card(
      elevation: 2,
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const Text(
              '预设文本',
              style: TextStyle(
                fontSize: 16,
                fontWeight: FontWeight.bold,
              ),
            ),
            const SizedBox(height: 12),
            Wrap(
              spacing: 8,
              runSpacing: 8,
              children: _presetTexts.map((text) {
                return ActionChip(
                  label: Text(
                    text.length > 20 ? '${text.substring(0, 20)}...' : text,
                    style: const TextStyle(fontSize: 12),
                  ),
                  onPressed: () {
                    _textController.text = text;
                    _speak();
                  },
                );
              }).toList(),
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildHistoryCard() {
    return Card(
      elevation: 2,
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const Text(
              '朗读历史',
              style: TextStyle(
                fontSize: 16,
                fontWeight: FontWeight.bold,
              ),
            ),
            const SizedBox(height: 12),
            ..._history.map((text) {
              return Padding(
                padding: const EdgeInsets.only(bottom: 8),
                child: Row(
                  children: [
                    const Icon(Icons.history, size: 16, color: Colors.grey),
                    const SizedBox(width: 8),
                    Expanded(
                      child: Text(
                        text,
                        style: const TextStyle(fontSize: 13),
                        maxLines: 1,
                        overflow: TextOverflow.ellipsis,
                      ),
                    ),
                    TextButton(
                      onPressed: () {
                        _textController.text = text;
                        _speak();
                      },
                      child: const Text('朗读'),
                    ),
                  ],
                ),
              );
            }).toList(),
          ],
        ),
      ),
    );
  }
}

五、OpenHarmony 适配要点

5.1 语言代码格式

在 OpenHarmony 平台,语言代码使用标准格式:

语言代码 说明
zh-CN 中文(简体)
zh-TW 中文(繁体)
en-US 英语(美国)
en-GB 英语(英国)
ja-JP 日语
ko-KR 韩语

5.2 语速范围

语速范围为 0.0 到 1.0:

  • 0.0:最慢
  • 0.5:正常
  • 1.0:最快

5.3 音调范围

音调范围为 0.5 到 2.0:

  • 0.5:最低
  • 1.0:正常
  • 2.0:最高

六、常见问题

Q1: 语音朗读失败?

原因: 文本为空或语言不支持。

解决方案:

if (text.isEmpty) {
  print('文本不能为空');
  return;
}

final isAvailable = await _flutterTts.isLanguageAvailable('zh-CN');
if (!isAvailable) {
  print('该语言不可用');
  return;
}

Q2: 如何等待朗读完成?

解决方案:

await _flutterTts.awaitSpeakCompletion(true);
await _flutterTts.speak('这是一段文本');
print('朗读完成');

Q3: 如何获取支持的语言列表?

解决方案:

final languages = await _flutterTts.getLanguages;
print('支持的语言: $languages');

Q4: 暂停后如何继续?

解决方案:

// 暂停
await _flutterTts.pause();

// 继续(调用 speak 即可)
await _flutterTts.speak('');

Q5: 如何获取语音播放进度?

解决方案:

_flutterTts.setProgressHandler((text, start, end, word) {
  print('当前朗读: $word');
  print('进度: $start - $end');
});

Q6: 如何切换不同的语音?

解决方案:

final voices = await _flutterTts.getVoices;
for (var voice in voices) {
  print('语音: ${voice['name']}, 语言: ${voice['locale']}');
}

// 设置特定语音
await _flutterTts.setVoice({'name': 'zh-CN', 'locale': 'zh-CN'});

七、总结

flutter_tts 是一个功能强大的文字转语音插件,在 OpenHarmony 平台的适配已经非常成熟。通过本文的介绍,你应该已经掌握了:

  1. FlutterTts 的核心 API 和使用方法
  2. 文字转语音的完整流程
  3. 语速、音调、音量的调节方法
  4. 多语言支持和语音选择
  5. 朗读状态控制和进度回调
  6. 完整的应用级别语音播报助手实现
  7. OpenHarmony 平台的适配要点和注意事项
  8. 常见问题和解决方案

在实际开发中,建议根据具体需求选择合适的语言和语音设置,注意错误处理和状态管理。对于复杂的语音场景,可以结合其他库实现更丰富的功能。

提示:更多 OpenHarmony 适配的 Flutter 三方库信息,请访问 开源鸿蒙跨平台开发者社区 获取最新资源和技术支持。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐