Flutter视频会议插件jitsi_meet_flutter_sdk的使用
Flutter视频会议插件jitsi_meet_flutter_sdk的使用
Jitsi Meet Flutter SDK
Jitsi Meet Flutter SDK 提供了与 Jitsi Meet 应用相同的用户体验,以 Flutter 插件的形式呈现,使您可以在自己的 Flutter 应用中嵌入和自定义 Jitsi Meet。
支持的平台
平台 | 支持 | 备注 |
---|---|---|
Android | ✅ | 最低 API 级别为 24 |
iOS | ✅ | 最低支持版本为 13.4 |
Web | ❌ |
示例应用
如果您想了解将 Jitsi Meet Flutter SDK 集成到 Flutter 应用程序是多么简单,请参考 示例应用程序仓库。
安装
添加依赖
通过命令行添加依赖:
$ flutter pub add jitsi_meet_flutter_sdk
上述命令会将以下内容添加到项目的 pubspec.yaml
文件中(您也可以手动添加):
dependencies:
jitsi_meet_flutter_sdk: ^10.3.0
安装
从终端安装包:
$ flutter pub get
导入文件
在 Dart 代码中导入以下文件:
import 'package:jitsi_meet_flutter_sdk/jitsi_meet_flutter_sdk.dart';
使用方法
加入会议
首先创建一个 JitsiMeet
对象,然后调用它的 join
方法并传递一个 JitsiMeetConferenceOptions
对象。
var jitsiMeet = JitsiMeet();
var options = JitsiMeetConferenceOptions(room: 'jitsiIsAwesome');
jitsiMeet.join(options);
配置
iOS
确保在 ios
目录下的 Podfile
中设置 iOS 版本为 15.1 或更高
:
platform :ios, '15.1'
该插件请求摄像头和麦克风访问权限,请确保在 ios/Runner
目录下的 Info.plist
文件中包含所需的 NSCameraUsageDescription
和 NSMicrophoneUsageDescription
条目:
<key>NSCameraUsageDescription</key>
<string>The app needs access to your camera for meetings.</string>
<key>NSMicrophoneUsageDescription</key>
<string>The app needs access to your microphone for meetings.</string>
要使用屏幕共享功能需要集成 Broadcast Upload Extension
。请参阅:屏幕共享集成。
Android
前往 android/app/build.gradle
并确保 minSdkVersion
设置为 至少 24
:
android {
...
defaultConfig {
...
minSdkVersion 24
}
}
application:label
字段与 Jitsi Meet Android SDK 的冲突。前往 android/app/src/main/AndroidManifest.xml
并在 application 标签中添加 tools 库和 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
JitsiMeet
JitsiMeet
类是 SDK 的入口点。它用于启动会议屏幕、发送和接收所有事件。
join(JitsiMeetConferenceOptions options, [JitsiMeetEventListener? listener])
加入具有给定选项的会议,并可选地提供一个监听器。
options
: 会议选项。listener
: 由原生 SDK 触发的事件监听器。
hangUp()
本地参与者离开当前会议。
setAudioMuted(bool muted)
根据 muted
参数设置本地参与者的音频静音状态。
setVideoMuted(bool muted)
根据 muted
参数设置本地参与者的视频静音状态。
sendEndpointTextMessage({String? to, required String message})
通过数据通道向特定参与者或所有参与者发送消息。如果 to
参数为空,则消息将发送给会议中的所有参与者。
toggleScreenShare(bool enabled)
根据 enabled
参数设置本地参与者的屏幕共享状态。
openChat([String? to])
打开聊天对话框。如果 to
包含有效的 participantId
,则将打开与该特定参与者的私人聊天。
sendChatMessage({String? to, required String message})
向特定参与者或所有参与者发送聊天消息。如果 to
参数为空,则消息将发送给会议中的所有参与者。
closeChat()
关闭聊天对话框。
retrieveParticipantsInfo()
发送触发 participantsInfoRetrieved
事件的消息,该事件包含参与者信息。
JitsiMeetConferenceOptions
此对象封装了加入会议时可以调整的所有选项。
var options = JitsiMeetConferenceOptions(
serverURL: "https://meet.jit.si",
room: "jitsiIsAwesomeWithFlutter",
configOverrides: {
"startWithAudioMuted": false,
"startWithVideoMuted": false,
"subject" : "Jitsi with Flutter",
},
featureFlags: {
"unsaferoomwarning.enabled": false
},
userInfo: JitsiMeetUserInfo(
displayName: "Flutter user",
email: "user@example.com"
),
);
JitsiMeetEventListener
此类旨在作为来自原生 SDK 事件的监听器。它将接收事件处理程序作为参数。
示例监听器
var listener = JitsiMeetEventListener(
conferenceJoined: (url) {
debugPrint("conferenceJoined: url: $url");
},
participantJoined: (email, name, role, participantId) {
debugPrint(
"participantJoined: email: $email, name: $name, role: $role, "
"participantId: $participantId",
);
participants.add(participantId!);
},
chatMessageReceived: (senderId, message, isPrivate) {
debugPrint(
"chatMessageReceived: senderId: $senderId, message: $message, "
"isPrivate: $isPrivate",
);
},
readyToClose: () {
debugPrint("readyToClose");
},
);
参考资料
在构建此项目时受到了 jitsi_meet_wrapper 的启发。
示例代码
以下是 example/lib/main.dart
中的完整示例代码:
import 'package:flutter/material.dart';
import 'package:jitsi_meet_flutter_sdk/jitsi_meet_flutter_sdk.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
bool audioMuted = true;
bool videoMuted = true;
bool screenShareOn = false;
List<String> participants = [];
final _jitsiMeetPlugin = JitsiMeet();
join() async {
var options = JitsiMeetConferenceOptions(
room: "testgabigabi",
configOverrides: {
"startWithAudioMuted": true,
"startWithVideoMuted": true,
},
featureFlags: {
FeatureFlags.addPeopleEnabled: true,
FeatureFlags.welcomePageEnabled: true,
FeatureFlags.preJoinPageEnabled: true,
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: JitsiMeetUserInfo(
displayName: "Gabi",
email: "gabi.borlea.1@gmail.com",
avatar:
"https://avatars.githubusercontent.com/u/57035818?s=400&u=02572f10fe61bca6fc20426548f3920d53f79693&v=4"),
);
var listener = JitsiMeetEventListener(
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 _jitsiMeetPlugin.join(options, listener);
}
hangUp() async {
await _jitsiMeetPlugin.hangUp();
}
setAudioMuted(bool? muted) async {
var a = await _jitsiMeetPlugin.setAudioMuted(muted!);
debugPrint("$a");
setState(() {
audioMuted = muted;
});
}
setVideoMuted(bool? muted) async {
var a = await _jitsiMeetPlugin.setVideoMuted(muted!);
debugPrint("$a");
setState(() {
videoMuted = muted;
});
}
sendEndpointTextMessage() async {
var a = await _jitsiMeetPlugin.sendEndpointTextMessage(message: "HEY");
debugPrint("$a");
for (var p in participants) {
var b =
await _jitsiMeetPlugin.sendEndpointTextMessage(to: p, message: "HEY");
debugPrint("$b");
}
}
toggleScreenShare(bool? enabled) async {
await _jitsiMeetPlugin.toggleScreenShare(enabled!);
setState(() {
screenShareOn = enabled;
});
}
openChat() async {
await _jitsiMeetPlugin.openChat();
}
sendChatMessage() async {
var a = await _jitsiMeetPlugin.sendChatMessage(message: "HEY1");
debugPrint("$a");
for (var p in participants) {
a = await _jitsiMeetPlugin.sendChatMessage(to: p, message: "HEY2");
debugPrint("$a");
}
}
closeChat() async {
await _jitsiMeetPlugin.closeChat();
}
retrieveParticipantsInfo() async {
var a = await _jitsiMeetPlugin.retrieveParticipantsInfo();
debugPrint("$a");
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
TextButton(
onPressed: join,
child: const Text("Join"),
),
TextButton(onPressed: hangUp, child: const Text("Hang Up")),
Row(children: [
const Text("Set Audio Muted"),
Checkbox(
value: audioMuted,
onChanged: setAudioMuted,
),
]),
Row(children: [
const Text("Set Video Muted"),
Checkbox(
value: videoMuted,
onChanged: setVideoMuted,
),
]),
TextButton(
onPressed: sendEndpointTextMessage,
child: const Text("Send Hey Endpoint Message To All")),
Row(children: [
const Text("Toggle Screen Share"),
Checkbox(
value: screenShareOn,
onChanged: toggleScreenShare,
),
]),
TextButton(
onPressed: openChat, child: const Text("Open Chat")),
TextButton(
onPressed: sendChatMessage,
child: const Text("Send Chat Message to All")),
TextButton(
onPressed: closeChat, child: const Text("Close Chat")),
TextButton(
onPressed: retrieveParticipantsInfo,
child: const Text("Retrieve Participants Info")),
]),
)),
);
}
}
更多关于Flutter视频会议插件jitsi_meet_flutter_sdk的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter视频会议插件jitsi_meet_flutter_sdk的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,下面是一个关于如何在Flutter项目中使用jitsi_meet_flutter_sdk
插件来集成Jitsi Meet视频会议功能的代码示例。这个插件允许你在Flutter应用中嵌入Jitsi Meet视频会议界面。
1. 添加依赖
首先,在你的pubspec.yaml
文件中添加jitsi_meet_flutter_sdk
依赖:
dependencies:
flutter:
sdk: flutter
jitsi_meet_flutter_sdk: ^x.y.z # 请替换为最新版本号
2. 导入插件
在你需要使用Jitsi Meet功能的Dart文件中导入插件:
import 'package:jitsi_meet_flutter_sdk/jitsi_meet_flutter_sdk.dart';
3. 配置Jitsi Meet视图
接下来,你可以使用JitsiMeetView
或JitsiMeetActivity
(取决于你使用的是iOS还是Android,或者是否希望在Flutter内部处理UI)来启动视频会议。
示例:使用JitsiMeetView
在Flutter中嵌入Jitsi Meet
import 'package:flutter/material.dart';
import 'package:jitsi_meet_flutter_sdk/jitsi_meet_flutter_sdk.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: JitsiMeetScreen(),
);
}
}
class JitsiMeetScreen extends StatefulWidget {
@override
_JitsiMeetScreenState createState() => _JitsiMeetScreenState();
}
class _JitsiMeetScreenState extends State<JitsiMeetScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Jitsi Meet Integration'),
),
body: Center(
child: JitsiMeetView(
options: JitsiMeetViewOptions(
room: 'https://meet.jit.si/YourMeetingRoom', // 替换为你的会议室URL
userDisplayName: 'Flutter User',
userInfo: <String, dynamic>{
'email': 'user@example.com',
},
audioOnly: false,
welcomePageEnabled: true,
toolbarButtons: [
JitsiMeetToolbarButton.hangup,
],
),
listener: (JitsiMeetViewState state) {
// 处理会议状态变化,例如会议结束等
print('JitsiMeetView state: $state');
},
onConferenceTerminated: () {
// 会议结束时回调
print('Conference terminated');
},
),
),
);
}
}
4. 配置Android权限(如果需要)
如果你的应用需要在Android设备上访问摄像头或麦克风,你需要在AndroidManifest.xml
中添加相应的权限:
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
5. 运行应用
确保你已经连接了开发设备或启动了模拟器,然后在命令行中运行以下命令来构建并运行你的Flutter应用:
flutter run
注意事项
- 确保你已经在Jitsi Meet服务器上配置了会议室。
- 根据你的需求调整
JitsiMeetViewOptions
中的参数。 - 在实际项目中,处理用户权限时要考虑用户体验和隐私保护。
这个示例展示了如何在Flutter应用中集成Jitsi Meet进行视频会议。根据你的具体需求,你可能需要进一步定制和扩展此功能。