Flutter视频会议插件moi_meet_flutter_sdk的使用
Flutter视频会议插件moi_meet_flutter_sdk的使用
概述
moi_meet_flutter_sdk
提供了与 Moi Meet
应用相同的功能体验,它以 Flutter 插件的形式存在,使得你可以在自己的 Flutter 应用中嵌入并自定义视频会议功能。
支持的平台
平台 | 支持情况 | 备注 |
---|---|---|
Android | ✅ | 最低 API 级别为 24 |
iOS | ✅ | 最低支持版本为 13.4 |
Web | ❌ |
示例应用
如果你希望看到如何轻松地将 moi_meet_flutter_sdk
集成到 Flutter 应用中,可以查看以下示例仓库:
https://github.com/ANASDAVOODTK/moi-meet-sdk-samples
安装
添加依赖
在命令行中添加依赖:
$ flutter pub add moi_meet_flutter_sdk
这将在你的项目 pubspec.yaml
文件中添加以下内容(也可以手动添加):
dependencies:
moi_meet_flutter_sdk: ^10.2.1
安装
从终端安装包:
$ flutter pub get
导入文件
在 Dart 代码中导入以下文件:
import 'package:moi_meet_flutter_sdk/moi_meet_flutter_sdk.dart';
使用
加入会议
首先,创建一个 MoiMeet
对象,然后调用 join
方法,并传入一个 MoiMeetConferenceOptions
对象。
var moiMeet = MoiMeet();
var options = MoiMeetConferenceOptions(room: 'moiIsAwesome');
moiMeet.join(options);
配置
iOS
确保在 ios/Podfile
中设置 iOS 版本为 15.1 或更高:
platform :ios, '15.1'
插件请求相机和麦克风访问权限。确保在 ios/Runner/Info.plist
文件中包含所需的条目:
<key>NSCameraUsageDescription</key>
<string>该应用需要访问您的摄像头进行会议。</string>
<key>NSMicrophoneUsageDescription</key>
<string>该应用需要访问您的麦克风进行会议。</string>
Android
在 android/app/build.gradle
中确保 minSdkVersion
至少为 24:
android {
...
defaultConfig {
...
minSdkVersion 24
}
}
在 android/app/src/main/AndroidManifest.xml
中添加工具库和 tools:replace="android:label"
到应用标签:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application
tools:replace="android:label"
android:label="sample_app"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
...
</application>
</manifest>
使用API
MoiMeet
MoiMeet
类是 SDK 的入口点,用于启动会议屏幕、发送和接收所有事件。
-
构造函数
MoiMeet()
-
加入会议
join(MoiMeetConferenceOptions options, [MoiMeetEventListener? listener])
参数:
options
:会议选项。listener
:事件监听器,用于接收由原生 SDK 触发的事件。
-
挂断
hangUp()
-
设置音频静音
setAudioMuted(bool muted)
-
设置视频静音
setVideoMuted(bool muted)
-
发送数据通道消息
sendEndpointTextMessage({String? to, required String message})
-
切换屏幕共享
toggleScreenShare(bool enabled)
-
打开聊天对话框
openChat([String? to])
-
发送聊天消息
sendChatMessage({String? to, required String message})
-
关闭聊天对话框
closeChat()
-
获取参与者信息
retrieveParticipantsInfo()
MoiMeetConferenceOptions
此对象封装了加入会议时可以调整的所有选项。
示例:
var options = MoiMeetConferenceOptions(
serverURL: "https://meet.aioman.org",
room: "moiIsAwesomeWithFlutter",
configOverrides: {
"startWithAudioMuted": false,
"startWithVideoMuted": false,
"subject" : "Moi with Flutter",
},
featureFlags: {
"unsaferoomwarning.enabled": false
},
userInfo: MoiMeetUserInfo(
displayName: "Flutter user",
email: "user@example.com"
),
);
MoiMeetUserInfo
MoiMeetUserInfo({String displayName, String email, String avatar})
参数:
displayName
:显示名称。email
:电子邮件地址。avatar
:头像 URL。
MoiMeetEventListener
这是一个用于接收来自原生 SDK 事件的监听器类。
-
会议已加入
conferenceJoined(String url)
-
会议终止
conferenceTerminated(String url, Object? error)
-
即将加入会议
conferenceWillJoin(String url)
-
参与者已加入
participantJoined(String? email, String? name, String? role, String? participantId)
-
参与者已离开
participantLeft(String? participantId)
-
音频静音状态改变
audioMutedChanged(bool muted)
-
视频静音状态改变
videoMutedChanged(bool muted)
-
接收到文本消息
endpointTextMessageReceived(String senderId, String message)
-
屏幕共享状态改变
screenShareToggled(String participantId, bool sharing)
-
接收到聊天消息
chatMessageReceived(String senderId, String message, bool isPrivate, String? timestamp)
-
聊天对话框打开或关闭
chatToggled(bool isOpen)
-
获取参与者信息
participantsInfoRetrieved(String participantsInfo)
-
SDK 准备关闭
readyToClose()
示例代码
以下是完整的示例代码:
// ignore_for_file: avoid_print
import 'package:flutter/material.dart';
import 'package:moi_meet_flutter_sdk/moi_meet_flutter_sdk.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
[@override](/user/override)
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final TextEditingController meetingIdController = TextEditingController();
final TextEditingController userNameController = TextEditingController();
bool audioMuted = true;
bool videoMuted = true;
bool screenShareOn = false;
List<String> participants = [];
final _moiMeetPlugin = MoiMeet();
join({
required String roomId,
required String displayName,
}) async {
var options = MoiMeetConferenceOptions(
serverURL: "https://meet.aioman.org",
room: roomId,
configOverrides: {
"startWithAudioMuted": true,
"startWithVideoMuted": true,
},
featureFlags: {
FeatureFlags.addPeopleEnabled: true,
FeatureFlags.welcomePageEnabled: false,
FeatureFlags.preJoinPageEnabled: false,
FeatureFlags.unsafeRoomWarningEnabled: true,
FeatureFlags.resolution: FeatureFlagVideoResolutions.resolution720p,
FeatureFlags.audioFocusDisabled: true,
FeatureFlags.audioMuteButtonEnabled: true,
FeatureFlags.audioOnlyButtonEnabled: true,
FeatureFlags.calenderEnabled: true,
FeatureFlags.callIntegrationEnabled: true,
FeatureFlags.carModeEnabled: true,
FeatureFlags.closeCaptionsEnabled: true,
FeatureFlags.conferenceTimerEnabled: true,
FeatureFlags.chatEnabled: true,
FeatureFlags.filmstripEnabled: true,
FeatureFlags.fullScreenEnabled: true,
FeatureFlags.helpButtonEnabled: true,
FeatureFlags.inviteEnabled: true,
FeatureFlags.androidScreenSharingEnabled: true,
FeatureFlags.speakerStatsEnabled: true,
FeatureFlags.kickOutEnabled: true,
FeatureFlags.liveStreamingEnabled: true,
FeatureFlags.lobbyModeEnabled: true,
FeatureFlags.meetingNameEnabled: true,
FeatureFlags.meetingPasswordEnabled: true,
FeatureFlags.notificationEnabled: true,
FeatureFlags.overflowMenuEnabled: true,
FeatureFlags.pipEnabled: true,
FeatureFlags.pipWhileScreenSharingEnabled: true,
FeatureFlags.preJoinPageHideDisplayName: true,
FeatureFlags.raiseHandEnabled: true,
FeatureFlags.reactionsEnabled: true,
FeatureFlags.recordingEnabled: true,
FeatureFlags.replaceParticipant: true,
FeatureFlags.securityOptionEnabled: true,
FeatureFlags.serverUrlChangeEnabled: true,
FeatureFlags.settingsEnabled: true,
FeatureFlags.tileViewEnabled: true,
FeatureFlags.videoMuteEnabled: true,
FeatureFlags.videoShareEnabled: true,
FeatureFlags.toolboxEnabled: true,
FeatureFlags.iosRecordingEnabled: true,
FeatureFlags.iosScreenSharingEnabled: true,
FeatureFlags.toolboxAlwaysVisible: true,
},
userInfo: MoiMeetUserInfo(
displayName: displayName,
email: "gabi.borlea.1@gmail.com",
avatar: "https://cdn3d.iconscout.com/3d/premium/thumb/middle-eastern-arab-man-avatar-3d-icon-download-in-png-blend-fbx-gltf-file-formats--profile-view-people-person-different-pack-icons-8779384.png?f=webp"),
);
var listener = MoiMeetEventListener(
conferenceJoined: (url) {
debugPrint("conferenceJoined: url: $url");
},
conferenceTerminated: (url, error) {
debugPrint("conferenceTerminated: url: $url, error: $error");
},
conferenceWillJoin: (url) {
debugPrint("conferenceWillJoin: url: $url");
},
participantJoined: (email, name, role, participantId) {
debugPrint(
"participantJoined: email: $email, name: $name, role: $role, "
"participantId: $participantId",
);
participants.add(participantId!);
},
participantLeft: (participantId) {
debugPrint("participantLeft: participantId: $participantId");
},
audioMutedChanged: (muted) {
debugPrint("audioMutedChanged: isMuted: $muted");
},
videoMutedChanged: (muted) {
debugPrint("videoMutedChanged: isMuted: $muted");
},
endpointTextMessageReceived: (senderId, message) {
debugPrint(
"endpointTextMessageReceived: senderId: $senderId, message: $message");
},
screenShareToggled: (participantId, sharing) {
debugPrint(
"screenShareToggled: participantId: $participantId, "
"isSharing: $sharing",
);
},
chatMessageReceived: (senderId, message, isPrivate, timestamp) {
debugPrint(
"chatMessageReceived: senderId: $senderId, message: $message, "
"isPrivate: $isPrivate, timestamp: $timestamp",
);
},
chatToggled: (isOpen) => debugPrint("chatToggled: isOpen: $isOpen"),
participantsInfoRetrieved: (participantsInfo) {
debugPrint(
"participantsInfoRetrieved: participantsInfo: $participantsInfo, ");
},
readyToClose: () {
debugPrint("readyToClose");
},
);
await _moiMeetPlugin.join(options, listener);
}
hangUp() async {
await _moiMeetPlugin.hangUp();
}
setAudioMuted(bool? muted) async {
var a = await _moiMeetPlugin.setAudioMuted(muted!);
debugPrint("$a");
setState(() {
audioMuted = muted;
});
}
setVideoMuted(bool? muted) async {
var a = await _moiMeetPlugin.setVideoMuted(muted!);
debugPrint("$a");
setState(() {
videoMuted = muted;
});
}
sendEndpointTextMessage() async {
var a = await _moiMeetPlugin.sendEndpointTextMessage(message: "HEY");
debugPrint("$a");
for (var p in participants) {
var b = await _moiMeetPlugin.sendEndpointTextMessage(to: p, message: "HEY");
debugPrint("$b");
}
}
toggleScreenShare(bool? enabled) async {
await _moiMeetPlugin.toggleScreenShare(enabled!);
setState(() {
screenShareOn = enabled;
});
}
openChat() async {
await _moiMeetPlugin.openChat();
}
sendChatMessage() async {
var a = await _moiMeetPlugin.sendChatMessage(message: "HEY1");
debugPrint("$a");
for (var p in participants) {
a = await _moiMeetPlugin.sendChatMessage(to: p, message: "HEY2");
debugPrint("$a");
}
}
closeChat() async {
await _moiMeetPlugin.closeChat();
}
retrieveParticipantsInfo() async {
var a = await _moiMeetPlugin.retrieveParticipantsInfo();
debugPrint("$a");
}
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
title: const Text('Moi Meet'),
centerTitle: true,
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
// Network Image at the Top
Container(
margin: const EdgeInsets.only(bottom: 32.0),
child: Image.network(
'https://meet.aioman.org/images/moi/moi-meet-logo.png',
height: 150,
width: 150,
fit: BoxFit.cover,
),
),
// Meeting ID TextField
TextField(
controller: meetingIdController,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Meeting ID',
hintText: 'Enter Meeting ID',
),
),
const SizedBox(height: 16.0),
// User Name TextField
TextField(
controller: userNameController,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Your Name',
hintText: 'Enter Your Name',
),
),
const Spacer(),
// Join Now Button at the Bottom
SizedBox(
width: double.infinity,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xff637ada),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0),
),
),
onPressed: () {
// Handle join button press here
String meetingId = meetingIdController.text;
String userName = userNameController.text;
// Add logic to join the meeting using meetingId and userName
print(
'Joining meeting with ID: $meetingId and Username: $userName');
join(displayName: userName, roomId: meetingId);
},
child: const Text(
'Join Now',
style: TextStyle(color: Colors.white),
),
),
),
],
),
),
));
}
}
更多关于Flutter视频会议插件moi_meet_flutter_sdk的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter视频会议插件moi_meet_flutter_sdk的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,关于如何在Flutter项目中使用moi_meet_flutter_sdk
插件来实现视频会议功能,下面是一个基本的代码示例。请确保你已经在pubspec.yaml
文件中添加了该插件的依赖,并且已经运行了flutter pub get
来安装它。
首先,确保你的pubspec.yaml
包含以下依赖:
dependencies:
flutter:
sdk: flutter
moi_meet_flutter_sdk: ^最新版本号 # 请替换为实际可用的最新版本号
然后,你可以按照以下步骤在你的Flutter应用中集成和使用moi_meet_flutter_sdk
。
1. 初始化插件
在你的Flutter应用的入口文件(通常是main.dart
)中,初始化moi_meet_flutter_sdk
。
import 'package:flutter/material.dart';
import 'package:moi_meet_flutter_sdk/moi_meet_flutter_sdk.dart';
void main() {
// 初始化 SDK,这里可以传入一些配置参数,具体参考 SDK 文档
MoiMeetFlutterSdk.instance.init(
config: MoiMeetConfig(
// 替换为你的实际配置,例如服务器地址、API密钥等
serverUrl: 'https://your-server-url.com',
apiKey: 'your-api-key',
),
);
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: VideoMeetingPage(),
);
}
}
2. 创建视频会议页面
接下来,创建一个新的页面来展示视频会议界面。
import 'package:flutter/material.dart';
import 'package:moi_meet_flutter_sdk/moi_meet_flutter_sdk.dart';
class VideoMeetingPage extends StatefulWidget {
@override
_VideoMeetingPageState createState() => _VideoMeetingPageState();
}
class _VideoMeetingPageState extends State<VideoMeetingPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Video Meeting'),
),
body: Center(
child: ElevatedButton(
onPressed: () async {
// 加入会议,传入会议ID等信息
String meetingId = 'your-meeting-id';
String userName = 'your-user-name';
try {
await MoiMeetFlutterSdk.instance.joinMeeting(
meetingId: meetingId,
userName: userName,
);
} catch (e) {
// 处理错误,例如网络问题、会议不存在等
print('Error joining meeting: $e');
}
},
child: Text('Join Meeting'),
),
),
);
}
@override
void dispose() {
// 当页面销毁时,确保释放 SDK 资源
MoiMeetFlutterSdk.instance.dispose();
super.dispose();
}
}
3. 处理会议事件(可选)
你可能需要监听一些会议事件,例如用户加入、离开、发言等。你可以通过设置一个事件监听器来实现。
@override
void initState() {
super.initState();
// 设置事件监听器
MoiMeetFlutterSdk.instance.onMeetingEvent.listen((event) {
// 根据事件类型处理逻辑
if (event is UserJoinedEvent) {
print('User joined: ${event.userName}');
} else if (event is UserLeftEvent) {
print('User left: ${event.userName}');
}
// 处理其他事件类型...
});
}
注意事项
- 错误处理:确保在生产代码中妥善处理各种可能的错误,例如网络错误、认证失败等。
- UI优化:根据实际需求优化UI,例如添加加载指示器、错误提示等。
- 权限管理:确保应用有适当的权限,例如相机和麦克风权限。
这个示例提供了一个基本的框架,你可能需要根据moi_meet_flutter_sdk
的具体文档和功能需求进行进一步的定制和扩展。