帮你快速理解、总结文档立即下载

Flutter

最近更新时间:2026-10-20 17:32:16
本文档已由 AI 辅助审校
我的收藏
本文将介绍如何使用 TRTC Flutter SDK(tencent_rtc_sdk)快速实现一个基础的音视频通话。

支持平台

平台
Android
iOS
HarmonyOS
Windows
macOS
是否支持






前提条件

开通服务

1. 登录 TRTC 控制台,单击创建应用。如果您已经完成创建,可以跳过该操作。
2. 在创建应用成功后,您可以在应用管理中获取到您的 SDKAppID 和 SDK 密钥。



SDKAppID:控制台创建的 TRTC 应用的唯一标识。
SDK 密钥:用于计算 UserSig(用户进入音视频房间的鉴权凭证)。

获取 UserSig

调试阶段:可以在控制台辅助工具中的 UserSig 生成工具里输入 userId 生成临时 UserSig,也可以参见 用户鉴权 在本地计算。
正式环境:UserSig 必须由您的业务服务端计算并下发给客户端。
注意:
请勿将 SDK 密钥写入客户端代码或打包进 App,否则密钥可能被反编译窃取,导致流量被盗用。

环境准备

Flutter 3.22 及以上版本。
Android 端开发:
Android Studio 最新稳定版本。
App 要求 Android 5.0(API 级别 21)及以上版本设备。
iOS 端开发:
Xcode 15 及以上版本,App 要求 iOS 12.0 及以上版本设备。
请确保您的项目已设置有效的开发者签名。
Windows 端开发:
Visual Studio 2022 及以上版本,并勾选“使用 C++ 的桌面开发”工作负载。
macOS 端开发:
Xcode 15 及以上版本,App 要求 macOS 10.14 及以上版本。
HarmonyOS 端开发:
DevEco Studio 5.0 及以上版本,HarmonyOS SDK API 12(5.0.0)及以上。
鸿蒙版 Flutter SDK:官方 Flutter SDK 不支持 HarmonyOS,需要使用 OpenHarmony 社区维护的 flutter_flutter,克隆后切换到与您 Flutter 版本对应的 oh-* 分支,并按仓库 README 配置 DevEco Studio 相关环境变量,通过 flutter doctor -v 确认已识别 ohos 工具链。
普通 flutter create 生成的工程没有 ohos/ 目录,请使用鸿蒙版 Flutter SDK 在工程根目录执行 flutter create --platforms ohos . 生成。

步骤1:导入 SDK

方式一:命令行添加(推荐)
方式二:手动添加
1. 通过以下命令安装组件 tencent_rtc_sdk:
flutter pub add tencent_rtc_sdk
2. 在 Android / HarmonyOS 上申请麦克风和相机运行时权限,需要增加依赖 permission_handler:
flutter pub add permission_handler
1. 打开 pubspec.yaml 文件,添加 tencent_rtc_sdk(最新版本可以查询 https://pub.dev/packages/tencent_rtc_sdk)和 permission_handler 依赖:
dependencies:
# TRTC Flutter SDK 依赖项,请替换为 pub.dev 上的最新版本
tencent_rtc_sdk: ^<最新版本>
# 权限处理插件依赖项
permission_handler: ^11.0.0
2. 添加依赖并保存文件后,打开终端,在包含 pubspec.yaml 的 Flutter 工程根目录下执行如下命令:
flutter pub get
说明:
HarmonyOS 工程需要使用适配 OpenHarmony 的 permission_handler,请在 pubspec.yaml 中按如下方式引入:
permission_handler:
git:
url: "https://gitcode.com/openharmony-sig/flutter_permission_handler.git"
path: "permission_handler"

步骤2:配置项目

iOS
Android
macOS
Windows
HarmonyOS
增加麦克风和相机权限说明
1. 需要在 ios/Runner/Info.plist 的第一级<dict>目录下加入相机和麦克风的权限说明。SDK 首次访问相机和麦克风时,系统会自动弹出授权框:
<key>NSCameraUsageDescription</key>
<string>授权摄像头权限才能正常视频通话</string>
<key>NSMicrophoneUsageDescription</key>
<string>授权麦克风权限才能正常语音通话</string>
2. (可选)如果您希望在 iOS 上也使用 permission_handler 主动申请权限,需要开启对应权限的编译宏,否则 Permission.camera.request() 会直接返回拒绝且不会弹出系统授权弹窗。请将以下内容合并到 ios/Podfile 已有的 post_install 中,不要重复声明 post_install:
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)

target.build_configurations.each do |config|
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
'$(inherited)',
## permission_handler: 启用摄像头权限
'PERMISSION_CAMERA=1',
## permission_handler: 启用麦克风权限
'PERMISSION_MICROPHONE=1',
]
end
end
end
配置 Release 符号裁剪(必需)
SDK 通过 Dart FFI 在运行时按名称查找 TRTC 的 C 符号。Xcode 打 Release 包时默认会裁掉这些全局符号,导致 Debug 正常、Release 运行时报 symbol not found。请在 Xcode 中选择 Runner > TARGETS > Runner > Build Settings,将 Release 配置下的以下两项修改为:
Deployment Postprocessing:Yes
Strip Style:Non-Global Symbols
增加麦克风和相机权限申请
1. 打开 android/app/src/main/AndroidManifest.xml 文件。
2. 在其中添加如下权限:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.CAMERA" />
<!-- 蓝牙耳机支持:Android 11 及以下使用 BLUETOOTH,Android 12 及以上使用 BLUETOOTH_CONNECT -->
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />
解决 so 冲突
如果工程中有多个依赖都包含 libliteavsdk.so,编译时会报 so 重复。请在 android/app/build.gradle(或 build.gradle.kts)中添加:
// build.gradle(Groovy)
android {
packagingOptions {
pickFirst 'lib/**/libliteavsdk.so'
}
}
// build.gradle.kts(Kotlin DSL)
android {
packaging {
jniLibs {
pickFirsts += "lib/**/libliteavsdk.so"
}
}
}
混淆配置
如果 release 包开启了混淆(minifyEnabled true),请在 android/app/proguard-rules.pro 中添加如下规则,并确保 buildTypes.release 的 proguardFiles 引用了该文件:
-keep class com.tencent.** { *; }
增加麦克风和相机权限说明
需要在 macos/Runner/Info.plist 的第一级<dict>目录下加入相机和麦克风的权限说明:
<key>NSCameraUsageDescription</key>
<string>授权摄像头权限才能正常视频通话</string>
<key>NSMicrophoneUsageDescription</key>
<string>授权麦克风权限才能正常语音通话</string>
配置沙盒权限(必需)
Flutter macOS 工程默认开启 App Sandbox,请在 macos/Runner/DebugProfile.entitlements 和 macos/Runner/Release.entitlements 两个文件中都添加以下内容,否则 App 无法访问摄像头、麦克风和网络:
<key>com.apple.security.device.camera</key>
<true/>
<key>com.apple.security.device.audio-input</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
添加屏幕分享系统依赖库(可选,仅使用屏幕分享时需要,要求 macOS 12.3 及以上)
1. 打开 .xcworkspace 工程文件后,在 Xcode 的导航栏中点击左侧的 Project Navigator,点击 Runner 并确保在编辑区域选择正确的 TARGETS。
2. 在 General 选项卡的 Frameworks, Libraries, and Embedded Content 部分添加 ScreenCaptureKit.framework。

无需额外配置。
增加麦克风和相机权限申请
在 ohos/entry/src/main/module.json5 的 module 节点下添加 requestPermissions。以下 reason 复用了默认工程 ohos/entry/src/main/resources/base/element/string.json 中已有的 module_desc,可直接编译:
"requestPermissions": [
{ "name": "ohos.permission.INTERNET" },
{
"name": "ohos.permission.CAMERA",
"reason": "$string:module_desc",
"usedScene": { "abilities": [], "when": "inuse" }
},
{
"name": "ohos.permission.MICROPHONE",
"reason": "$string:module_desc",
"usedScene": { "abilities": [], "when": "inuse" }
}
]
说明:
reason 引用的字符串必须在 string.json 中存在,否则编译失败。如需为相机和麦克风分别展示授权理由,请在 ohos/entry/src/main/resources/base/element/string.json 的 string 数组中新增条目(如 { "name": "camera_reason", "value": "用于视频通话" }),再将上面的 reason 改为 $string:camera_reason。

步骤3:创建 TRTC 实例并注册事件监听

1. 引入头文件并声明成员变量:
import 'package:tencent_rtc_sdk/trtc_cloud.dart';
import 'package:tencent_rtc_sdk/trtc_cloud_def.dart';
import 'package:tencent_rtc_sdk/trtc_cloud_listener.dart';
late TRTCCloud trtcCloud;
late TRTCCloudListener listener;
2. 在异步方法中(例如在 initState 中调用的初始化方法)创建 TRTC 实例并注册事件监听。建议在进房前一次性注册所有需要的回调:
Future<void> initTRTC() async {
// 创建 TRTC 实例(单例)
trtcCloud = await TRTCCloud.sharedInstance();

// 创建 TRTCCloudListener 实例,根据需要实现对应的回调
listener = TRTCCloudListener(
// SDK 不可恢复的错误,如进房失败、设备打开失败等
onError: (errCode, errMsg) {
debugPrint('onError: $errCode, $errMsg');
},
// 进房结果:result > 0 表示进房成功(值为耗时,单位 ms),result < 0 为错误码
onEnterRoom: (result) {
debugPrint(result > 0 ? '进房成功' : '进房失败: $result');
},
// 远端用户开启 / 关闭视频,详见步骤7
onUserVideoAvailable: (userId, available) {
onRemoteVideoChanged(userId, available);
},
// 退房完成,详见步骤9
onExitRoom: (reason) {
releaseTRTC();
},
);

// 注册监听器,将 listener 绑定到 trtcCloud 实例
trtcCloud.registerListener(listener);
}

步骤4:进入房间

1. 在 Android 和 HarmonyOS 设备上,需要在进房前主动申请 CAMERA 和 MICROPHONE 权限;iOS 和 macOS 会在 SDK 首次访问设备时由系统自动弹出授权框。
import 'dart:io';
import 'package:permission_handler/permission_handler.dart';

Future<bool> requestPermissions() async {
if (!(Platform.isAndroid || TRTCPlatform.isOhos)) return true;
final statuses = await [Permission.camera, Permission.microphone].request();
return statuses.values.every((status) => status.isGranted);
}
说明:
此处权限申请使用了第三方仓库 permission_handler。
2. 在 TRTC 控制台 中获取您应用的 SDKAppID,并参见 用户鉴权 获取 UserSig。
3. 设置进房参数 TRTCParams 后,调用 enterRoom 即可进入房间。
参数
类型
描述
sdkAppId
int
您在 TRTC 控制台中创建的应用程序的 SDKAppID。
userId
String
您指定的用户 ID,同一房间内不能重复。
userSig
String
与 userId 对应的用户签名,请参见 UserSig。
strRoomId / roomId
String / int
房间号,二选一。两者同时填写时以 roomId 为准。roomId 取值范围为 1~4294967294。strRoomId 最长 64 字节,仅支持以下字符:大小写英文字母(a-z、A-Z)、数字(0-9)、空格及 ! # $ % & ( ) + - : ; < = . > ? @ [ ] ^ _ { } | ~ ,,包含中文等其他字符会导致进房失败。
scene
TRTCAppScene
应用场景,enterRoom 的第二个参数。音视频通话请使用 videoCall / audioCall;互动直播请使用 live / voiceChatRoom,并通过 TRTCParams.role 指定主播或观众角色。
trtcCloud.enterRoom(
TRTCParams(
sdkAppId: sdkAppId, // 请替换为您的 SDKAppID
userId: userId, // 请替换为您的 userId
userSig: userSig, // 请替换为该 userId 对应的 UserSig
strRoomId: roomId, // 请替换为您的房间号
),
TRTCAppScene.videoCall,
);
说明:
多个客户端互通,需要使用相同的 sdkAppId、相同的房间号和不同的 userId(不支持多端使用相同的 userId 同时进入同一个音视频房间)。
同一个 sdkAppId 下请统一使用数字房间号或字符串房间号,不要混用:数字 123 和字符串 "123" 是两个不同的房间。
enterRoom 必须与 exitRoom 成对调用。

步骤5:打开摄像头

1. 在页面的 build 方法中添加本地视频渲染控件 TRTCCloudVideoView,并在 onViewCreated 回调中拿到 viewId 后再调用 startLocalPreview 开启摄像头预览:
import 'package:tencent_rtc_sdk/trtc_cloud_video_view.dart';
TRTCCloudVideoView(
key: const ValueKey('local'),
onViewCreated: (viewId) {
// true:前置摄像头;false:后置摄像头(二选一,仅移动端有效)
trtcCloud.startLocalPreview(true, viewId);
},
),
说明:
viewId 为视频渲染控件 TRTCCloudVideoView 的唯一标识符,只有在 onViewCreated 回调之后才可用,因此 startLocalPreview 需在该回调中(或之后)调用。
请在 TRTCCloud.sharedInstance() 完成之后再构建 TRTCCloudVideoView。SDK 会在实例创建时确定渲染方式(macOS / Windows 使用纹理渲染),过早创建的控件可能无法正常显示画面。
2. (可选)在调用 startLocalPreview 打开摄像头预览之前,您可以通过调用 setLocalRenderParams 设置本地预览的渲染参数:
参数
参数说明
取值
取值说明
rotation
图像的顺时针旋转角度。支持 90、180 以及 270 旋转角度,默认值:TRTCVideoRotation.rotation0。
不旋转。
顺时针旋转90度。
顺时针旋转180度。
顺时针旋转270度。
fillMode
画面填充模式。填充(画面可能会被拉伸裁剪)或适应(画面可能会有黑边),默认值:TRTCVideoFillMode.fill。
填充模式:即将画面内容居中等比缩放以充满整个显示区域,超出显示区域的部分将会被裁剪掉,此模式下画面可能不完整。
适应模式:即按画面长边进行缩放以适应显示区域,短边部分会被填充为黑色,此模式下图像完整但可能留有黑边。
缩放填充模式:即无论画面的宽高比,都会被拉伸或压缩以完全填充显示区域,此模式下画面宽高比可能会被改变,导致渲染画面变形。
画面镜像模式。默认值:TRTCVideoMirrorType.auto。
自动模式:如果正使用前置摄像头则开启镜像,如果是后置摄像头则不开启镜像(仅适用于移动设备)。
强制开启镜像,不论当前使用的是前置摄像头还是后置摄像头。
强制关闭镜像,不论当前使用的是前置摄像头还是后置摄像头。
// 设置本地预览渲染参数
trtcCloud.setLocalRenderParams(
TRTCRenderParams(
fillMode: TRTCVideoFillMode.fill,
mirrorType: TRTCVideoMirrorType.auto,
rotation: TRTCVideoRotation.rotation0,
),
);
调用 stopLocalPreview 关闭摄像头预览并停止推送本地视频。
trtcCloud.stopLocalPreview();
3. (仅移动端)您可以通过 TXDeviceManager 类实现“切换前后摄像头”、“设置对焦模式”、“闪光灯”等设备扩展功能。
import 'package:tencent_rtc_sdk/tx_device_manager.dart';
// 获取设备管理器实例
TXDeviceManager manager = trtcCloud.getDeviceManager();

// 切换前后摄像头:当前为前置则切到后置,反之切到前置
manager.switchCamera(!manager.isFrontCamera());
// 获取设备管理器实例
TXDeviceManager manager = trtcCloud.getDeviceManager();

// 如果设备支持自动对焦(人脸自动识别),则开启自动对焦
if (manager.isAutoFocusEnabled()) {
manager.enableCameraAutoFocus(true);
}
// 获取设备管理器实例
TXDeviceManager manager = trtcCloud.getDeviceManager();

// 开启闪光灯(仅在使用后置摄像头时有效)
manager.enableCameraTorch(true);

// 关闭闪光灯
manager.enableCameraTorch(false);

步骤6:打开麦克风

调用 startLocalAudio 开启麦克风采集,请根据您的需求选择以下的一个音质参数:
参数
描述
人声模式:单声道;编码码率:16kbps;具备几个模式中最强的弱网抗性,适合语音通话为主的场景,例如在线会议、语音通话等。
默认模式:单声道;编码码率:50kbps;介于 speech 和 music 之间的档位,SDK 默认档位,推荐选择。
音乐模式:全频带立体声;编码码率:128kbps;适合需要高保真传输音乐的场景,例如在线 K 歌、音乐直播等。
// 开启麦克风采集,使用默认音质(推荐)
trtcCloud.startLocalAudio(TRTCAudioQuality.defaultMode);
// 以语音为主的场景(如在线会议),可使用人声模式,获得更强的弱网抗性
trtcCloud.startLocalAudio(TRTCAudioQuality.speech);
调用 stopLocalAudio 关闭麦克风采集并停止推送本地音频。
trtcCloud.stopLocalAudio();

步骤7:播放/停止视频流

1. 在步骤3注册的监听中处理 onUserVideoAvailable 回调:收到 onUserVideoAvailable(userId, true) 时,表示该用户的画面已有可播放的视频帧到达,此时为该用户添加渲染控件;收到 false 时停止播放并移除控件。
final List<String> remoteUsers = [];

void onRemoteVideoChanged(String userId, bool available) {
if (!mounted) return;
setState(() {
if (available) {
if (!remoteUsers.contains(userId)) remoteUsers.add(userId);
} else {
remoteUsers.remove(userId);
trtcCloud.stopRemoteView(userId, TRTCVideoStreamType.big);
}
});
}
2. 在 build 方法中为每个远端用户创建 TRTCCloudVideoView,并在 onViewCreated 回调中调用 startRemoteView 播放该用户的视频画面:
for (final userId in remoteUsers)
TRTCCloudVideoView(
key: ValueKey('remote_$userId'),
onViewCreated: (viewId) {
// 播放远端用户的主路(大画面)视频
trtcCloud.startRemoteView(userId, TRTCVideoStreamType.big, viewId);
},
),
3. 您也可以通过 stopAllRemoteView 停止播放所有远端用户的视频。
// 停止播放所有远端用户的视频画面
trtcCloud.stopAllRemoteView();

步骤8:播放/停止音频流

默认情况下,SDK 会自动播放远端用户的音频,您无需调用任何 API。
如需静音或恢复远端声音,可以调用 muteRemoteAudio / muteAllRemoteAudio:
// 静音指定远端用户(remoteUserId 为远端用户的 userId)
trtcCloud.muteRemoteAudio(remoteUserId, true);

// 静音所有远端用户
trtcCloud.muteAllRemoteAudio(true);
// 取消静音指定远端用户
trtcCloud.muteRemoteAudio(remoteUserId, false);

// 取消静音所有远端用户
trtcCloud.muteAllRemoteAudio(false);

步骤9:退出房间

调用 exitRoom 退出当前房间:
trtcCloud.stopLocalPreview();
trtcCloud.stopLocalAudio();
trtcCloud.exitRoom();
TRTC SDK 会在退房结束后通过步骤3中注册的 onExitRoom 回调通知您,您可以在该回调中注销监听并销毁实例:
void releaseTRTC() {
trtcCloud.unRegisterListener(listener);
TRTCCloud.destroySharedInstance();
}
注意:
exitRoom 是异步的,SDK 会在释放摄像头、麦克风等设备资源后回调 onExitRoom。如需再次进房,请在收到 onExitRoom 后再调用 enterRoom,否则可能出现设备被占用等问题。

步骤10:完整示例

以下是一个可直接运行的单页面示例。请将顶部常量替换为您自己的信息,然后在两台设备上使用不同的 userId 进入同一房间。
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:tencent_rtc_sdk/trtc_cloud.dart';
import 'package:tencent_rtc_sdk/trtc_cloud_def.dart';
import 'package:tencent_rtc_sdk/trtc_cloud_listener.dart';
import 'package:tencent_rtc_sdk/trtc_cloud_video_view.dart';

const int sdkAppId = 0; // 请替换为您的 SDKAppID
const String userId = 'user_a'; // 请替换为您的 userId
const String userSig = ''; // 请替换为该 userId 对应的 UserSig
const String roomId = '123abc'; // 请替换为您的房间号

void main() => runApp(const MaterialApp(home: VideoCallPage()));

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

@override
State<VideoCallPage> createState() => _VideoCallPageState();
}

class _VideoCallPageState extends State<VideoCallPage> {
TRTCCloud? trtcCloud;
late final TRTCCloudListener listener;
final List<String> remoteUsers = [];

@override
void initState() {
super.initState();
listener = TRTCCloudListener(
onError: (errCode, errMsg) => debugPrint('onError: $errCode, $errMsg'),
onEnterRoom: (result) =>
debugPrint(result > 0 ? '进房成功' : '进房失败: $result'),
onUserVideoAvailable: onRemoteVideoChanged,
onExitRoom: (reason) {
trtcCloud?.unRegisterListener(listener);
TRTCCloud.destroySharedInstance();
},
);
start();
}

Future<void> start() async {
if (!await requestPermissions()) {
debugPrint('未获得相机或麦克风权限');
return;
}
final cloud = await TRTCCloud.sharedInstance();
cloud.registerListener(listener);
cloud.enterRoom(
TRTCParams(
sdkAppId: sdkAppId,
userId: userId,
userSig: userSig,
strRoomId: roomId,
),
TRTCAppScene.videoCall,
);
cloud.startLocalAudio(TRTCAudioQuality.defaultMode);
if (mounted) setState(() => trtcCloud = cloud);
}

Future<bool> requestPermissions() async {
if (!(Platform.isAndroid || TRTCPlatform.isOhos)) return true;
final statuses = await [Permission.camera, Permission.microphone].request();
return statuses.values.every((status) => status.isGranted);
}

void onRemoteVideoChanged(String uid, bool available) {
if (!mounted) return;
setState(() {
if (available) {
if (!remoteUsers.contains(uid)) remoteUsers.add(uid);
} else {
remoteUsers.remove(uid);
trtcCloud?.stopRemoteView(uid, TRTCVideoStreamType.big);
}
});
}

@override
void dispose() {
trtcCloud?.stopLocalPreview();
trtcCloud?.stopLocalAudio();
trtcCloud?.exitRoom();
super.dispose();
}

@override
Widget build(BuildContext context) {
final cloud = trtcCloud;
return Scaffold(
appBar: AppBar(title: const Text('Room: $roomId')),
body: cloud == null
? const Center(child: CircularProgressIndicator())
: GridView.count(
crossAxisCount: 2,
children: [
TRTCCloudVideoView(
key: const ValueKey('local'),
onViewCreated: (viewId) =>
cloud.startLocalPreview(true, viewId),
),
for (final uid in remoteUsers)
TRTCCloudVideoView(
key: ValueKey('remote_$uid'),
onViewCreated: (viewId) => cloud.startRemoteView(
uid, TRTCVideoStreamType.big, viewId),
),
],
),
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.red,
onPressed: () => Navigator.of(context).maybePop(),
child: const Icon(Icons.call_end),
),
);
}
}
更完整的示例工程请参见 GitHub: TRTC_Flutter。如需实现互动直播(主播 / 观众角色)、屏幕分享等进阶功能,请参见 API 概览。

常见问题

您可以在 API 概览 查看所有函数列表及其描述。
如果您在接入和使用中遇到问题,请参见 常见问题。
说明:
如果您在 iOS 运行 release 版本时遇到找不到符号的问题,请参见 iOS release 包运行时 [symbol not found]。