【Flutter】使用LiveKit和Flutter构建实时视频聊天应用
引言
在当今快速发展的数字世界中,实时视频通信已成为许多应用程序的核心功能。无论是远程工作、在线教育还是社交网络,高质量的实时视频功能都至关重要。LiveKit作为一个开源的WebRTC解决方案,提供了构建可扩展实时音视频应用所需的一切工具。结合Flutter的跨平台能力,我们可以轻松创建出色的视频聊天体验。
本文将带你了解如何使用LiveKit Server和LiveKit Flutter SDK构建一个实时视频聊天应用。
准备工作
- 设置LiveKit Server
首先,我们需要设置LiveKit服务器,这里直接用网上下载的https://github.com/livekit/livekit。
本地启动
请使用cmd运行
c:\Users\用户名\Documents\GithubProjects\livekit\livekit-server.exe --dev --bind 0.0.0.0
默认key是apikey,密码是secert。
记住你的API_KEY和API_SECRET,稍后客户端连接时会用到。
2. 创建Flutter项目
创建一个新的Flutter项目:
flutter create livekit_flutter_demo
cd livekit_flutter_demo
集成LiveKit Flutter SDK
- 添加依赖
在pubspec.yaml中添加LiveKit Flutter SDK:
dependencies:# LiveKit SDK用于实时音频/视频通信livekit_client: ^2.3.6livekit_components: ^1.1.1# 权限处理插件permission_handler: ^11.3.0crypto: ^3.0.6
然后运行:
flutter pub get
- 配置权限
对于Android,在AndroidManifest.xml中添加:
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
对于iOS,在Info.plist中添加:
<key>NSCameraUsageDescription</key>
<string>需要摄像头权限来进行视频通话</string>
<key>NSMicrophoneUsageDescription</key>
<string>需要麦克风权限来进行语音通话</string>
构建视频聊天界面
- 初始化LiveKit客户端
Future<Result<Room>> connectToRoom(String url, String token) async {final room = Room(roomOptions: RoomOptions(adaptiveStream: true));try {await room.prepareConnection(url, token);await room.connect(url, token);state = room;return Result.success(room);} catch (e) {state = null;return Result.failure(e);}}
2.生成token
token本应是服务器给,但是有时需要客户端生成,jwt形式。
auth_service.dart
import 'dart:convert';import 'package:crypto/crypto.dart';class AuthService {/// 生成视频通话的JWT令牌////// [roomName] - 房间名称/// [identity] - 用户标识/// [expiresIn] - 令牌有效期,可选值:/// - 1小时 (1h)/// - 6小时 (6h)/// - 24小时 (24h)/// - 168小时 (7天)/// - 720小时 (30天)/// - 8760小时 (1年)/// [key] - API密钥/// [secret] - API密钥对应的密钥static String generateVideoToken(String roomName, String identity,Duration expiresIn, String key, String secret) {final now = DateTime.now().toUtc();final nbf = now.millisecondsSinceEpoch ~/ 1000;final exp = now.add(expiresIn).millisecondsSinceEpoch ~/ 1000;final header = {'alg': 'HS256', 'typ': 'JWT'};final videoGrants = {'room': roomName,'roomJoin': true,'canPublish': true,'canSubscribe': true,};final claims = {'iss': key,'nbf': nbf,'exp': exp,'sub': identity,'video': videoGrants,};String base64UrlEncodeNoPadding(String str) =>base64Url.encode(utf8.encode(str)).replaceAll('=', '');final encodedHeader = base64UrlEncodeNoPadding(json.encode(header));final encodedPayload = base64UrlEncodeNoPadding(json.encode(claims));final message = '$encodedHeader.$encodedPayload';final hmac = Hmac(sha256, utf8.encode(secret));final digest = hmac.convert(utf8.encode(message));final signature = base64Url.encode(digest.bytes).replaceAll('=', '');return '$encodedHeader.$encodedPayload.$signature';}
}
一切配置到这,你就可以进入房间了。
3.启用麦克风和相机
await room.localParticipant?.setMicrophoneEnabled(true);await room.localParticipant?.setCameraEnabled(true);
4.视频推流
// 创建摄像头轨道final options = CameraCaptureOptions(cameraPosition: _isFrontCamera ? CameraPosition.front : CameraPosition.back,params: const VideoParameters(dimensions: VideoDimensions(640, 480)),final cameraTrack = await LocalVideoTrack.createCameraTrack(options);await localParticipant.publishVideoTrack(cameraTrack);
停止推流
// 停止推流try {for (final pub in localParticipant.videoTrackPublications) {if (pub.source == TrackSource.camera) {await localParticipant.unpublishAllTracks();}}} catch (e) {debugPrint('停止推流失败: $e');}
预览
VideoTrackRenderer(videoTrack,fit: RTCVideoViewObjectFit.RTCVideoViewObjectFitCover,)
查找房间人数
int getParticipantCount() {// 本地参与者(自己) + 远程参与者数量return 1 + room.remoteParticipants.length;
}