Flutter 快速开始与功能指南
Flutter:前置条件、安装、Token、加入频道、发布订阅、事件、错误处理与排障;接口名与签名在构建时取自公开 SDK 接口定义。
Flutter 端是 Dart 语言的 RtcEngine 形状(与 Android/iOS 同构):RtcEngine + RtcEngineEventHandler,返回值用 Future 包装。
前置条件
- Flutter 3.22+、Dart 3.4+。
- 各平台原生权限:Android 的
CAMERA/RECORD_AUDIO,iOS 的NSCameraUsageDescription/NSMicrophoneUsageDescription。 - 已拿到
appId与 Token 服务(见 控制台开通服务与获取凭证)。
安装
# pubspec.yaml —— 本地路径依赖
dependencies:
nimeet_rtc:
path: ../ni-meet/sdk/flutter获取 Token
Flutter 客户端不能持有 customerSecret;Token 由你的后端签发,Flutter 侧通过 TokenProvider 注入:
final provider = FallbackTokenProvider([
CallbackTokenProvider((channel, uid, role) => authApi.fetchRtcToken(channel, uid, role)),
StaticTokenProvider(Platform.environment['NIMEET_TEST_TOKEN'] ?? ''),
]);加入频道
import 'package:nimeet_rtc/nimeet_rtc.dart';
class MeetingController extends RtcEngineEventHandler {
late final RtcEngine engine;
Future<void> start(String appId, String token) async {
engine = await RtcEngine.create(RtcEngineConfig(appId: appId));
engine.registerEventHandler(this);
await engine.setChannelProfile(ChannelProfileType.channelProfileLiveBroadcasting);
await engine.enableVideo();
await engine.setupLocalVideo(const VideoCanvas(uid: 0));
await engine.startPreview();
await engine.joinChannel(
token: token,
channelId: 'weekly-sync',
uid: 10001,
options: const ChannelMediaOptions(clientRoleType: ClientRoleType.clientRoleBroadcaster),
);
}
@override
void onJoinChannelSuccess(RtcConnection connection, int elapsed) {
// 入会成功
}
@override
void onUserJoined(RtcConnection connection, int remoteUid, int elapsed) {
// 远端用户加入
}
@override
void onUserOffline(RtcConnection connection, int remoteUid, UserOfflineReasonType reason) {
// 远端用户离开
}
@override
void onTokenPrivilegeWillExpire(String token) {
// 续期后调用 engine.renewToken(newToken)
}
}发布与订阅
await engine.muteLocalAudioStream(true); // 静音麦克风
await engine.muteLocalVideoStream(true); // 关本地画面
await engine.enableLocalVideo(false); // 停止采集
await engine.updateChannelMediaOptions(options);屏幕共享:getScreenCaptureSources() 枚举源 → startScreenCapture(...);停止用 stopScreenCapture()。
事件
RtcEngineEventHandler 是回调类,覆盖 onJoinChannelSuccess、onUserJoined、onUserOffline、 onFirstRemoteVideoDecoded、onTokenPrivilegeWillExpire、onError、onConnectionStateChanged 等。 Flutter 回调默认回到主 isolate,可以直接 setState。
错误处理
Future失败会抛RtcException(携带code/sdkCode/message/retryable);- 异步错误走
onError回调; - 未实现能力抛
-4(ERR_NOT_SUPPORTED)。
排障
| 现象 | 原因 | 处理 |
|---|---|---|
| iOS 构建失败 | Pod 未安装 / 平台最低版本不满足 | cd ios && pod install,提升 platform :ios |
| 安卓黑屏 | 未申请运行时权限 | 宿主 App 主动请求 CAMERA/RECORD_AUDIO |
| 热重载后回调丢失 | handler 被重建 | 在 initState 注册、dispose 反注册 |
编译期 MissingPluginException | 原生端未注册插件 | 全量重启(flutter run 而不是热重载) |
| Token 过期后无法恢复 | 未处理 onTokenPrivilegeWillExpire | 续期并 renewToken |
下一步
平台信息
| 项 | 值 |
|---|---|
| 平台 | Flutter |
| 语言 | Dart |
| SDK 包 | nimeet_rtc |
| 接口版本 | 6.6.4 |
| 兼容参考 | 声网 flutter 端 API |
本端公开接口与声网 flutter 端 API 对齐;安装与运行要求见上面前置条件。
可用性
该端 SDK:正式可用。本页代码片段使用公开 API;运行时的能力边界以实际发布的 SDK 包为准。
加入频道链路
下列方法名、参数类型与返回值与同端 API 参考一致。一个平台若有多个重载,这里展示最常用的那一个;完整重载见同端 API 参考页。
| 步骤 | 接口 | 方法 | 重载数 |
|---|---|---|---|
| 订阅远端媒体 | BaseSpatialAudioEngine | muteRemoteAudioStream | 1 |
| 创建实例 / 初始化 | LocalSpatialAudioEngine | initialize | 1 |
| 续期 Token | MusicContentCenter | renewToken | 1 |
| 开启视频与本地预览 | RtcEngine | enableVideo | 1 |
| 加入频道 | RtcEngine | joinChannel | 1 |
| 离开频道 | RtcEngine | leaveChannel | 1 |
| 频道场景 | RtcEngine | setChannelProfile | 1 |
| 切换角色 | RtcEngine | setClientRole | 1 |
| 绑定本地画面 | RtcEngine | setupLocalVideo | 1 |
muteRemoteAudioStream(mute: int uid,required bool): Future
initialize(): Future
renewToken(token: String): Future
enableVideo(): Future
joinChannel(options: String token,required String channelId,required int uid,required ChannelMediaOptions): Future
leaveChannel(options?: LeaveChannelOptions?): Future
setChannelProfile(profile: ChannelProfileType): Future
setClientRole(options?: ClientRoleType role,ClientRoleOptions?): Future
setupLocalVideo(canvas: VideoCanvas): Future事件与回调
回调注册在 RtcEngineEventHandler 上;不同端的命名可能不同,完整清单见同端 API 参考页。
| 回调 | 签名 | 用途 |
|---|---|---|
onConnectionStateChanged | onConnectionStateChanged(connection: RtcConnection, state: ConnectionStateType, reason: ConnectionChangedReasonType): void | 入会结果 / 连接状态变化:据此更新 UI 并决定是否重连。 |
onUserJoined | onUserJoined(connection: RtcConnection, remoteUid: int, elapsed: int): void | 远端用户加入:分配画面容器。 |
onFirstRemoteVideoDecoded | onFirstRemoteVideoDecoded(connection: RtcConnection, remoteUid: int, width: int, height: int, elapsed: int): void | 远端视频状态:首帧解码后即可渲染。 |
onUserOffline | onUserOffline(connection: RtcConnection, remoteUid: int, reason: UserOfflineReasonType): void | 远端用户离开:释放容器与订阅。 |
onRequestToken | onRequestToken(connection: RtcConnection): void | Token 即将过期:调用服务端续期后 `renewToken`。 |
onError | onError(err: ErrorCodeType, msg: String): void | 运行时错误:`err` 为声网错误号,按错误码表分流。 |
onNetworkQuality | onNetworkQuality(connection: RtcConnection, remoteUid: int, txQuality: QualityType, rxQuality: QualityType): void | 网络质量:上报到水晶球或提示用户。 |
错误码
| 常量 | 值 |
|---|---|
RtcEngine | null |
errAborted | 20 |
errAdmGeneralError | 1005 |
errAdmInitPlayout | 1008 |
errAdmInitRecording | 1011 |
errAdmStartPlayout | 1009 |
errAdmStartRecording | 1012 |
errAdmStopPlayout | 1010 |
errAdmStopRecording | 1013 |
errAlreadyInUse | 19 |
errBitrateLimit | 115 |
errBufferTooSmall | 6 |
errClientIsBannedByServer | 123 |
errConnectionInterrupted | 111 |
errConnectionLost | 112 |
errDatastreamDecryptionFailed | 122 |
errDecryptionFailed | 120 |
errEncryptedStreamNotAllowedPublish | 130 |
errFailed | 1 |
errInitNetEngine | 21 |
errInvalidAppId | 101 |
errInvalidArgument | 2 |
errInvalidChannelName | 102 |
errInvalidState | 8 |
errInvalidToken | null |
errInvalidUserAccount | 134 |
errInvalidUserId | 121 |
errJoinChannelRejected | 17 |
errLeaveChannelRejected | 18 |
errLoadMediaEngine | 1001 |
errNoPermission | 9 |
errNoServerResources | 103 |
errNotInChannel | 113 |
errNotInitialized | 7 |
errNotReady | 3 |
errNotSupported | 4 |
errOk | 0 |
errPcmsendBufferoverflow | 201 |
errPcmsendFormat | 200 |
errRefused | 5 |
errResourceLimited | 22 |
errSetClientRoleNotAuthorized | 119 |
errSizeTooLarge | 114 |
errStreamMessageTimeout | 117 |
errTimedout | 10 |
errTokenExpired | 109 |
errTooManyDataStreams | 116 |
errVdmCameraNotAuthorized | 1501 |
平台 REST 层用 REST 错误码;SDK 层把连接/鉴权失败映射成声网错误号,映射表见 各端 SDK 错误标识。