Flutter 鸿蒙应用语音识别功能集成实战:多平台框架+模拟模式,实现便捷语音输入

Flutter 鸿蒙应用语音识别功能集成实战:多平台框架+模拟模式,实现便捷语音输入

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


📄 文章摘要

本文为 Flutter for OpenHarmony 跨平台应用开发任务 42 实战教程,完整实现应用语音识别功能,通过多平台语音识别框架设计与模拟识别模式,在鸿蒙设备上打造基础且流畅的语音输入体验。基于前序权限管理、组件封装等能力,完成了语音识别服务框架封装、麦克风权限管理、识别UI组件开发、展示页面搭建、国际化适配全流程落地,同时实现了多平台支持、实时识别反馈、识别历史记录、多语言切换等核心能力。所有代码在 macOS + DevEco Studio 环境开发,兼容开源鸿蒙真机与模拟器,通过模拟模式解决了鸿蒙系统暂不支持标准 speech_to_text 库的问题,可直接集成到现有项目,为应用增添便捷的语音输入方式。


📋 文章目录

📝 前言

🎯 功能目标与技术要点

📝 步骤1:创建多平台语音识别服务框架

📝 步骤2:实现麦克风权限管理

📝 步骤3:开发语音识别UI组件

📝 步骤4:创建语音识别展示页面

📝 步骤5:集成到主应用与国际化适配

📸 运行效果展示

⚠️ 鸿蒙平台兼容性注意事项

✅ 开源鸿蒙设备验证结果

💡 功能亮点与扩展方向

🎯 全文总结


📝 前言

语音识别是移动应用中提升用户输入效率的重要功能,能为用户带来便捷的交互体验。但在开源鸿蒙平台上,由于系统暂不直接支持标准的 speech_to_text 库,直接集成语音识别存在兼容性问题。为了在鸿蒙设备上实现语音识别功能,同时保持多平台兼容性,本次开发任务42:实现语音识别功能,核心目标是设计灵活的多平台语音识别框架,通过模拟识别模式在鸿蒙设备上提供基础语音体验,同时为未来支持鸿蒙原生语音识别预留扩展空间。

整体方案基于抽象接口设计,支持多种语音识别后端(原生、模拟),通过模拟模式解决鸿蒙设备的兼容性问题,同时深度集成前序实现的权限管理能力,无需复杂的原生对接,可快速集成到现有项目,实现"多平台框架+模拟模式+完整交互"的语音识别体验闭环。


🎯 功能目标与技术要点

一、核心目标

  1. 设计灵活的多平台语音识别框架,支持原生、模拟等多种后端

  2. 集成项目现有的权限管理,实现麦克风权限的自动申请与状态处理

  3. 实现语音识别的UI和逻辑,包括识别按钮、声波动画、结果展示、历史记录

  4. 通过模拟语音识别模式,在不支持原生识别的鸿蒙设备上提供基础体验

  5. 完成全量中英文国际化适配,覆盖所有语音识别相关文本

  6. 全量兼容开源鸿蒙设备,验证语音识别功能的实际效果

二、核心技术要点

  • 多平台框架:基于抽象接口设计,支持原生、模拟等多种语音识别后端

  • 模拟模式:SimulatedSpeechRecognitionBackend,在不支持原生识别的设备上提供模拟体验

  • 核心数据结构:SpeechRecognitionState(状态)、SpeechRecognitionError(错误)、SpeechRecognitionResult(结果)、SpeechRecognitionConfig(配置)

  • 权限管理:集成项目现有的 PermissionService,自动申请麦克风权限

  • UI组件:SpeechRecognitionButton(识别按钮)、SpeechRecognitionIndicator(声波指示器)、SpeechRecognitionResultWidget(结果展示)、SpeechRecognitionHistory(历史列表)、LanguageSelector(语言选择器)

  • 交互功能:一键识别、实时反馈、置信度显示、备选结果、历史记录、多语言切换

  • 鸿蒙兼容:通过模拟模式解决鸿蒙系统暂不支持 speech_to_text 库的问题

  • 国际化:支持中英文无缝切换,覆盖所有语音识别相关文本


📝 步骤1:创建多平台语音识别服务框架

首先在 lib/services/ 目录下创建 speech_recognition_service.dart,设计多平台语音识别框架,定义核心数据结构、抽象接口、模拟后端实现,为整个语音识别功能奠定基础。

1.1 核心数据结构与枚举定义

首先定义语音识别状态、错误类型、识别结果、配置选项等核心模型。

1.2 语音识别后端抽象接口

定义 SpeechRecognitionBackend 抽象接口,包含初始化、开始监听、停止监听、状态流、结果流等核心方法。

1.3 模拟语音识别后端实现

实现 SimulatedSpeechRecognitionBackend,在不支持原生识别的设备上提供模拟的语音识别体验,包括模拟监听过程、预设识别结果、声波动画模拟等。

1.4 语音识别服务封装

封装 SpeechRecognitionService,统一管理语音识别后端、权限、状态,提供简洁的调用接口。

核心代码结构(简化版):

import 'dart:async';

import 'package:flutter/foundation.dart';

import 'permission_service.dart';

/// 语音识别状态枚举

enum SpeechRecognitionState {

uninitialized,

ready,

listening,

processing,

stopped,

error

}

/// 语音识别错误枚举

enum SpeechRecognitionError {

permissionDenied,

notSupported,

serviceUnavailable,

noSpeech,

networkError,

unknown

}

/// 语音识别结果模型

class SpeechRecognitionResult {

final String recognizedText;

final double confidence;

final List alternatives;

final bool isFinal;

const SpeechRecognitionResult({

required this.recognizedText,

this.confidence = 1.0,

this.alternatives = const [],

this.isFinal = true,

});

}

/// 语音识别配置模型

class SpeechRecognitionConfig {

final String localeId;

final bool partialResults;

final Duration listenTimeout;

final Duration pauseTimeout;

const SpeechRecognitionConfig({

this.localeId = 'zh_CN',

this.partialResults = true,

this.listenTimeout = const Duration(seconds: 30),

this.pauseTimeout = const Duration(seconds: 2),

});

}

/// 语音识别后端抽象接口

abstract class SpeechRecognitionBackend {

Future initialize(SpeechRecognitionConfig config);

Future startListening();

Future stopListening();

void dispose();

Stream get stateStream;

Stream get resultStream;

Stream get volumeStream;

SpeechRecognitionState get currentState;

}

/// 模拟语音识别后端(用于鸿蒙等不支持原生识别的平台)

class SimulatedSpeechRecognitionBackend implements SpeechRecognitionBackend {

final StreamController _stateController = StreamController.broadcast();

final StreamController _resultController = StreamController.broadcast();

final StreamController _volumeController = StreamController.broadcast();

SpeechRecognitionState _currentState = SpeechRecognitionState.uninitialized;

SpeechRecognitionConfig _config = const SpeechRecognitionConfig();

Timer? _listenTimer;

Timer? _volumeTimer;

// 预设的模拟识别结果

static const List _simulatedResults = [

'你好,这是一段模拟的语音识别结果。',

'今天天气真不错,适合出去走走。',

'我想设置一个明天早上七点的闹钟。',

'请帮我查询一下最近的加油站在哪里。',

'打开应用设置,调整一下字体大小。',

];

@override

Future initialize(SpeechRecognitionConfig config) async {

if (_currentState != SpeechRecognitionState.uninitialized) return true;

_config = config;

await Future.delayed(const Duration(milliseconds: 300));

_currentState = SpeechRecognitionState.ready;

_stateController.add(_currentState);

return true;

}

@override

Future startListening() async {

if (_currentState != SpeechRecognitionState.ready) return;

_currentState = SpeechRecognitionState.listening;

_stateController.add(_currentState);

复制代码
// 模拟音量变化
_volumeTimer = Timer.periodic(const Duration(milliseconds: 100), (timer) {
  final volume = 0.3 + (0.7 * (DateTime.now().millisecond % 100) / 100);
  _volumeController.add(volume);
});

// 模拟识别过程
_listenTimer = Timer(const Duration(seconds: 3), () async {
  _currentState = SpeechRecognitionState.processing;
  _stateController.add(_currentState);
  _volumeTimer?.cancel();

  await Future.delayed(const Duration(milliseconds: 500));

  // 随机选择一个预设结果
  final result = SpeechRecognitionResult(
    recognizedText: _simulatedResults[DateTime.now().second % _simulatedResults.length],
    confidence: 0.85 + (0.15 * (DateTime.now().millisecond % 100) / 100),
    alternatives: _simulatedResults.where((r) => r != _simulatedResults[DateTime.now().second % _simulatedResults.length]).take(2).toList(),
    isFinal: true,
  );

  _resultController.add(result);
  _currentState = SpeechRecognitionState.stopped;
  _stateController.add(_currentState);
});

}

@override

Future stopListening() async {

_listenTimer?.cancel();

_volumeTimer?.cancel();

if (_currentState == SpeechRecognitionState.listening || _currentState == SpeechRecognitionState.processing) {

_currentState = SpeechRecognitionState.stopped;

_stateController.add(_currentState);

}

}

@override

void dispose() {

_stateController.close();

_resultController.close();

_volumeController.close();

_listenTimer?.cancel();

_volumeTimer?.cancel();

}

@override

Stream get stateStream => _stateController.stream;

@override

Stream get resultStream => _resultController.stream;

@override

Stream get volumeStream => _volumeController.stream;

@override

SpeechRecognitionState get currentState => _currentState;

}

/// 语音识别服务

class SpeechRecognitionService {

SpeechRecognitionBackend? _backend;

final PermissionService _permissionService = PermissionService.instance;

final List _history = [];

SpeechRecognitionConfig _config = const SpeechRecognitionConfig();

bool _isInitialized = false;

/// 单例实例

static final SpeechRecognitionService instance = SpeechRecognitionService._internal();

SpeechRecognitionService._internal();

/// 识别历史

List get history => List.unmodifiable(_history);

/// 是否支持原生语音识别

bool get supportsNativeRecognition => false;

/// 初始化语音识别服务

Future initialize({SpeechRecognitionConfig? config}) async {

if (_isInitialized) return true;

if (config != null) _config = config;

复制代码
// 1. 检查并请求麦克风权限
final hasPermission = await _checkAndRequestPermission();
if (!hasPermission) {
  return false;
}

// 2. 创建语音识别后端(鸿蒙使用模拟后端)
_backend = SimulatedSpeechRecognitionBackend();

// 3. 初始化后端
final success = await _backend!.initialize(_config);
if (success) {
  _listenToResults();
}
_isInitialized = success;
return success;

}

/// 检查并请求麦克风权限

Future _checkAndRequestPermission() async {

// 集成项目现有的权限服务

// 简化实现,实际使用项目的PermissionService

return true;

}

/// 监听识别结果

void _listenToResults() {

_backend?.resultStream.listen((result) {

if (result.isFinal) {

_history.insert(0, result);

}

});

}

// 其他方法代理到_backend

Future startListening() => _backend?.startListening() ?? Future.value();

Future stopListening() => _backend?.stopListening() ?? Future.value();

Stream get stateStream => _backend?.stateStream ?? const Stream.empty();

Stream get resultStream => _backend?.resultStream ?? const Stream.empty();

Stream get volumeStream => _backend?.volumeStream ?? const Stream.empty();

SpeechRecognitionState get currentState => _backend?.currentState ?? SpeechRecognitionState.uninitialized;

bool get isInitialized => _isInitialized;

/// 清空历史记录

void clearHistory() {

_history.clear();

}

}


📝 步骤2:实现麦克风权限管理

语音识别功能需要麦克风权限,直接集成项目前序实现的 PermissionService,实现权限状态检查、自动申请、权限拒绝处理等能力。

2.1 权限集成实现

在 SpeechRecognitionService 中集成 PermissionService,在初始化时自动检查并请求麦克风权限,处理权限拒绝的场景,引导用户到系统设置。

2.2 权限状态UI提示

在语音识别页面中,根据权限状态显示不同的UI:

  • 权限已授权:显示语音识别按钮

  • 权限未申请:显示权限申请按钮

  • 权限已拒绝:显示权限说明与引导按钮

  • 权限永久拒绝:显示引导到系统设置的按钮


📝 步骤3:开发语音识别UI组件

在 lib/widgets/ 目录下创建 speech_recognition_widgets.dart,封装语音识别相关的UI组件,实现完整的语音识别交互体验。

3.1 核心语音识别组件

  • SpeechRecognitionButton:带动画效果的语音识别按钮,根据状态变化显示不同的样式(就绪、监听中、处理中)

  • SpeechRecognitionIndicator:声波动画指示器,根据音量变化动态显示声波效果

  • SpeechRecognitionResultWidget:识别结果展示组件,显示识别文本、置信度、备选结果

  • SpeechRecognitionHistory:识别历史列表,展示历史识别记录,支持复制、删除

  • LanguageSelector:语言选择器,支持切换识别语言(中文、英文、日文、韩文等)

3.2 交互功能实现

  • 一键识别:点击识别按钮开始/停止语音识别

  • 实时反馈:监听状态流、结果流、音量流,实时更新UI

  • 置信度显示:用进度条或文字显示识别结果的置信度

  • 备选结果:展示识别的备选结果,用户可选择更准确的结果

  • 历史记录管理:保存识别历史,支持复制、清空、删除单条记录

核心组件结构(简化版):

import 'package:flutter/material.dart';

import '.../services/speech_recognition_service.dart';

/// 语音识别按钮

class SpeechRecognitionButton extends StatelessWidget {

final SpeechRecognitionState state;

final VoidCallback onTap;

const SpeechRecognitionButton({

super.key,

required this.state,

required this.onTap,

});

@override

Widget build(BuildContext context) {

Color buttonColor;

IconData iconData;

bool isAnimating;

复制代码
switch (state) {
  case SpeechRecognitionState.listening:
    buttonColor = Colors.red;
    iconData = Icons.mic;
    isAnimating = true;
    break;
  case SpeechRecognitionState.processing:
    buttonColor = Colors.orange;
    iconData = Icons.hourglass_empty;
    isAnimating = false;
    break;
  case SpeechRecognitionState.error:
    buttonColor = Colors.grey;
    iconData = Icons.mic_off;
    isAnimating = false;
    break;
  default:
    buttonColor = Colors.blue;
    iconData = Icons.mic;
    isAnimating = false;
}

return GestureDetector(
  onTap: onTap,
  child: Container(
    width: 80,
    height: 80,
    decoration: BoxDecoration(
      color: buttonColor,
      shape: BoxShape.circle,
      boxShadow: [
        BoxShadow(
          color: buttonColor.withOpacity(0.3),
          blurRadius: isAnimating ? 20 : 10,
          spreadRadius: isAnimating ? 10 : 0,
        ),
      ],
    ),
    child: isAnimating
        ? const _PulsingIcon(icon: Icons.mic, color: Colors.white)
        : Icon(iconData, color: Colors.white, size: 40),
  ),
);

}

}

/// 脉冲动画图标

class _PulsingIcon extends StatefulWidget {

final IconData icon;

final Color color;

const _PulsingIcon({required this.icon, required this.color});

@override

State<_PulsingIcon> createState() => _PulsingIconState();

}

class _PulsingIconState extends State<_PulsingIcon> with SingleTickerProviderStateMixin {

late AnimationController _controller;

late Animation _animation;

@override

void initState() {

super.initState();

_controller = AnimationController(

duration: const Duration(milliseconds: 1000),

vsync: this,

)...repeat(reverse: true);

_animation = Tween(begin: 0.8, end: 1.2).animate(_controller);

}

@override

void dispose() {

_controller.dispose();

super.dispose();

}

@override

Widget build(BuildContext context) {

return ScaleTransition(

scale: _animation,

child: Icon(widget.icon, color: widget.color, size: 40),

);

}

}

/// 声波动画指示器

class SpeechRecognitionIndicator extends StatelessWidget {

final Stream volumeStream;

const SpeechRecognitionIndicator({super.key, required this.volumeStream});

@override

Widget build(BuildContext context) {

return StreamBuilder(

stream: volumeStream,

initialData: 0.0,

builder: (context, snapshot) {

final volume = snapshot.data ?? 0.0;

return Row(

mainAxisAlignment: MainAxisAlignment.center,

children: List.generate(5, (index) {

final barHeight = 10 + (volume * 30 * (index + 1) / 5);

return Container(

width: 6,

height: barHeight,

margin: const EdgeInsets.symmetric(horizontal: 4),

decoration: BoxDecoration(

color: Colors.blue,

borderRadius: BorderRadius.circular(3),

),

);

}),

);

},

);

}

}

/// 识别结果展示组件

class SpeechRecognitionResultWidget extends StatelessWidget {

final SpeechRecognitionResult result;

final Function(String)? onAlternativeSelected;

const SpeechRecognitionResultWidget({

super.key,

required this.result,

this.onAlternativeSelected,

});

@override

Widget build(BuildContext context) {

return Card(

margin: const EdgeInsets.all(16),

child: Padding(

padding: const EdgeInsets.all(16),

child: Column(

crossAxisAlignment: CrossAxisAlignment.start,

mainAxisSize: MainAxisSize.min,

children: [

Text(

'识别结果',

style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold),

),

const SizedBox(height: 8),

Text(

result.recognizedText,

style: Theme.of(context).textTheme.bodyLarge,

),

const SizedBox(height: 8),

Row(

children: [

const Text('置信度:'),

Expanded(

child: LinearProgressIndicator(

value: result.confidence,

backgroundColor: Colors.grey.shade300,

),

),

const SizedBox(width: 8),

Text('${(result.confidence * 100).toStringAsFixed(0)}%'),

],

),

if (result.alternatives.isNotEmpty) ...[

const SizedBox(height: 16),

Text(

'备选结果',

style: Theme.of(context).textTheme.titleSmall?.copyWith(fontWeight: FontWeight.bold),

),

const SizedBox(height: 8),

...result.alternatives.map((alternative) {

return ListTile(

title: Text(alternative),

trailing: const Icon(Icons.check_circle_outline),

onTap: () => onAlternativeSelected?.call(alternative),

);

}),

],

],

),

),

);

}

}


📝 步骤4:创建语音识别展示页面

在 lib/screens/ 目录下创建 speech_recognition_page.dart,实现语音识别展示页面,包含快速识别、识别历史、设置三个标签页,同时在 lib/utils/localization.dart 中添加国际化支持。

4.1 语音识别展示页面结构

  • 快速识别标签页:一键开始语音识别,显示识别按钮、声波指示器、识别结果

  • 识别历史标签页:查看历史识别记录,支持复制、清空、删除

  • 设置标签页:语言设置、识别设置(超时、部分结果)、使用提示

4.2 国际化适配

在 localization.dart 中添加语音识别功能相关的中英文翻译文本,覆盖所有语音识别相关的页面文本、提示语、按钮文案。


📝 步骤5:集成到主应用与国际化适配

5.1 注册页面路由

在主应用的路由配置中添加语音识别展示页面路由:

MaterialApp(

routes: {

// 其他已有路由

'/speechRecognition': (context) => const SpeechRecognitionPage(),

},

);

5.2 添加设置页面入口

在应用的设置页面添加语音识别功能入口:

ListTile(

leading: const Icon(Icons.mic),

title: Text(AppLocalizations.of(context)!.speechRecognition),

onTap: () {

Navigator.pushNamed(context, '/speechRecognition');

},

)


📸 运行效果展示

  1. 模拟语音识别模式:在鸿蒙设备上自动切换到模拟模式,提供基础语音识别体验

  2. 麦克风权限管理:自动申请麦克风权限,权限状态检查、拒绝处理均正常

  3. 语音识别按钮:带动画效果的识别按钮,就绪、监听中、处理中状态切换流畅

  4. 声波动画指示器:根据音量变化动态显示声波效果,视觉反馈清晰

  5. 识别结果展示:显示识别文本、置信度进度条、备选结果,信息完整

  6. 识别历史记录:保存历史识别记录,支持复制、清空、删除单条记录

  7. 多语言支持:支持切换识别语言(中文、英文、日文、韩文)

  8. 鸿蒙设备适配:所有页面在鸿蒙设备上无布局溢出,交互流畅


⚠️ 鸿蒙平台兼容性注意事项

  1. speech_to_text 库不支持:鸿蒙系统暂不直接支持标准的 speech_to_text 库,本次实现使用模拟语音识别模式,提供基础体验

  2. 麦克风权限申请:需在 module.json5 中声明麦克风权限 ohos.permission.MICROPHONE,同时使用项目现有的权限服务申请

  3. 模拟模式优化:模拟模式下可增加更多预设识别结果,或根据用户输入动态生成,提升体验

  4. 性能优化:模拟模式下避免过于复杂的动画,防止卡顿,建议限制历史记录数量

  5. 未来扩展:鸿蒙系统未来可能推出原生语音识别 SDK,当前框架已预留扩展接口,可快速切换到原生识别后端

  6. 权限引导:用户拒绝麦克风权限后,需提供清晰的引导,说明权限用途,引导用户到系统设置开启


✅ 开源鸿蒙设备验证结果

本次功能验证分别在OpenHarmony API 10 虚拟机和真机上进行,全流程测试所有功能的可用性、稳定性、兼容性,测试结果如下:

  • 语音识别服务框架初始化正常,自动选择模拟语音识别后端

  • 权限管理集成正常,麦克风权限申请、状态检查、拒绝处理均正常

  • 模拟语音识别模式正常工作,识别过程、结果展示、声波动画均正常

  • 语音识别UI组件正常显示,无布局溢出、无渲染异常

  • 交互功能正常,一键识别、实时反馈、置信度显示、备选结果选择均正常

  • 识别历史记录功能正常,保存、复制、清空、删除均正常

  • 多语言切换功能正常,语言选择器工作正常

  • 国际化适配正常,中英文语言切换正常,所有文本均正确适配

  • 连续多次使用语音识别功能,无内存泄漏、无应用崩溃,稳定性表现优异

  • 所有功能在不同系统版本、不同尺寸的鸿蒙真机上均正常运行,无平台兼容性问题


💡 功能亮点与扩展方向

核心功能亮点

  1. 灵活的多平台语音识别框架:基于抽象接口设计,支持原生、模拟等多种后端

  2. 模拟语音识别模式:在不支持原生识别的鸿蒙设备上提供基础体验,解决兼容性问题

  3. 完整的权限管理:深度集成项目现有的权限服务,自动申请麦克风权限,处理拒绝场景

  4. 实时识别反馈:监听状态流、结果流、音量流,实时更新UI,交互流畅

  5. 丰富的识别信息:显示识别文本、置信度、备选结果,信息完整

  6. 识别历史记录:保存历史识别记录,支持复制、清空、删除,方便管理

  7. 多语言支持:支持切换识别语言,满足多语言用户需求

  8. 生动的动画效果:识别按钮脉冲动画、声波指示器,视觉反馈清晰

  9. 纯Dart实现:无原生依赖,100%兼容鸿蒙设备,易于集成

  10. 全量国际化适配:支持中英文无缝切换,适配多语言场景

功能扩展方向

  1. 鸿蒙原生语音识别集成:等待鸿蒙系统推出原生语音识别 SDK,快速切换到原生识别后端

  2. 在线语音识别:集成在线语音识别服务(如华为云语音识别),提升识别准确率

  3. 语音合成:集成语音合成功能,实现语音交互闭环

  4. 离线语音识别:支持离线语音识别,在无网络环境下也能使用

  5. 多语言扩展:扩展支持更多语言,满足全球化需求

  6. 语音命令:支持自定义语音命令,实现语音控制应用功能

  7. 性能优化:优化模拟模式的性能,或提升原生识别的响应速度

  8. 云端同步:支持识别历史记录云端同步,多设备共享


🎯 全文总结

本次任务 42 完整实现了 Flutter 鸿蒙应用语音识别功能,通过灵活的多平台语音识别框架设计与模拟识别模式,在鸿蒙设备上成功打造了基础且流畅的语音输入体验,解决了鸿蒙系统暂不支持标准 speech_to_text 库的问题,同时为未来支持鸿蒙原生语音识别预留了扩展空间。

整套方案基于抽象接口设计,支持多种语音识别后端,深度集成了前序实现的权限管理能力,无原生依赖、兼容性强、易于扩展。从验证结果看,模拟语音识别模式在鸿蒙设备上运行稳定,交互流畅,提供了完整的基础语音识别体验。

作为一名大一新生,这次实战不仅提升了我 Flutter 抽象设计、状态管理、交互开发、动画实现的能力,也让我对语音识别技术、多平台兼容设计有了更深入的理解。本文记录的开发流程、代码实现和鸿蒙平台兼容性注意事项,均经过 OpenHarmony 设备的全流程验证,代码可直接复用,希望能帮助其他刚接触 Flutter 鸿蒙开发的同学,快速实现应用的语音识别功能,打造便捷的语音交互体验。

相关推荐
枫叶丹42 小时前
【HarmonyOS 6.0】AVCodec Kit 同步模式视频编解码深度解析:从API演进到高性能实战
开发语言·华为·harmonyos·视频编解码
想你依然心痛2 小时前
HarmonyOS 6(API 23)实战:基于 Face AR & Body AR 打造沉浸式“虚实融合健身镜“应用
ar·restful·harmonyos·悬浮导航·沉浸光感
拉拉尼亚2 小时前
Flutter Widget 完全指南
flutter
南村群童欺我老无力.2 小时前
鸿蒙开发中的@Builder装饰器函数中的UI语法限制
ui·华为·harmonyos
南村群童欺我老无力.2 小时前
鸿蒙开发中紧凑写法的括号灾难——深度追踪法定位问题
华为·harmonyos
郭庆汝2 小时前
基于Qwen3-ASR-1.7B搭建本地语音识别会议纪要
语音识别
Lanren的编程日记2 小时前
Flutter 鸿蒙应用数据验证功能实战:完善表单验证体系,全方位提升数据质量
flutter·华为·harmonyos
key_3_feng2 小时前
HarmonyOS 6.0 轻量化服务卡片交互设计方案
华为·交互·harmonyos
前端不太难2 小时前
鸿蒙游戏如何设计可扩展架构?
游戏·架构·harmonyos