Flutter视频会议插件jitsi_meeting_plus的使用

发布于 1周前 作者 ionicwang 来自 Flutter

Flutter视频会议插件jitsi_meeting_plus的使用

此插件是从以下地址克隆的: https://pub.dev/packages/jitsi_meet

Jitsi Meet插件用于Flutter。支持Android和iOS平台。

“Jitsi Meet是一款开源(Apache)WebRTC JavaScript应用程序,使用Jitsi Videobridge来提供高质量、安全且可扩展的视频会议。”

更多信息,请访问: https://github.com/jitsi/jitsi-meet

目录


配置

iOS

注意:示例可在XCode 12.2 和 Flutter 1.22.4下编译。

Podfile

确保在Podfile中包含以下内容,指定平台版本为11.0或以上:

platform :ios, '11.0'
Info.plist

添加NSCameraUsageDescription和NSMicrophoneUsageDescription到Info.plist文件中:

<key>NSCameraUsageDescription</key>
<string>$(PRODUCT_NAME) MyApp需要访问您的相机进行会议。</string>
<key>NSMicrophoneUsageDescription</key>
<string>$(PRODUCT_NAME) MyApp需要访问您的麦克风进行会议。</string>

Android
Gradle

将构建工具gradle的依赖项设置为最低3.6.3:

dependencies {
    classpath 'com.android.tools.build:gradle:3.6.3' <!-- 升级此 -->
    classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}

将gradle wrapper设置为最低5.6.4:

distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip <!-- 升级此 -->

在你的项目的build.gradle文件中添加以下行以支持Java 1.8兼容性:

compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
}
AndroidManifest.xml

Jitsi Meet的SDK AndroidManifest.xml会与你的项目冲突,特别是application:label字段。要解决这个问题,请进入android/app/src/main/AndroidManifest.xml,添加工具库和tools:replace="android:label"到application标签中:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="yourpackage.com"
    xmlns:tools="http://schemas.android.com/tools">
    <application 
        tools:replace="android:label"  
        android:name="your.application.name"
        android:label="My Application"
        android:icon="@mipmap/ic_launcher">
        ...
    </application>
...
</manifest>
最小SDK版本23

android/app/build.gradle文件中更新最小SDK版本为23:

defaultConfig {
    applicationId "com.gunschu.jitsi_meet_example"
    minSdkVersion 23 //Required for Jitsi
    targetSdkVersion 28
    versionCode flutterVersionCode.toInteger()
    versionName flutterVersionName
}
Proguard

Jitsi的SDK启用了Proguard,但如果没有proguard-rules.pro文件,你的发布apk将缺少Flutter Wrapper和react-native代码。在你的Flutter项目的android/app/build.gradle文件中添加Proguard支持:

buildTypes {
    release {
        // TODO: 添加你的签名配置以进行发布构建。
        // 目前使用调试密钥,以便运行 `flutter run --release`。
        signingConfig signingConfigs.debug
        
        // 添加以下三行以启用Proguard
        minifyEnabled true
        useProguard true
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
}

然后,在同一目录下创建一个名为proguard-rules.pro的文件。参考示例应用的proguard-rules.pro文件以了解需要粘贴的内容。

注意

如果你不创建proguard-rules.pro文件,则当你尝试加入会议或会议屏幕试图打开时,你的应用可能会崩溃。你将在logcat中看到以下错误之一:

## 应用崩溃 ##
java.lang.RuntimeException: Parcel android.os.Parcel@8530c57: Unmarshalling unknown type code 7536745 at offset 104
    at android.os.Parcel.readValue(Parcel.java:2747)
    at android.os.Parcel.readSparseArrayInternal(Parcel.java:3118)
    at android.os.Parcel.readSparseArray(Parcel.java:2351)
    .....
## 会议无法打开,返回到前一个屏幕 ##
W/unknown:ViewManagerPropertyUpdater: Could not find generated setter for class com.BV.LinearGradient.LinearGradientManager
W/unknown:ViewManagerPropertyUpdater: Could not find generated setter for class com.facebook.react.uimanager.g
W/unknown:ViewManagerPropertyUpdater: Could not find generated setter for class com.facebook.react.views.art.ARTGroupViewManager
W/unknown:ViewManagerPropertyUpdater: Could not find generated setter for class com.facebook.react.views.art.a
.....

加入会议

_joinMeeting() async {
    try {
      FeatureFlag featureFlag = FeatureFlag();
      featureFlag.welcomePageEnabled = false;
      featureFlag.resolution = FeatureFlagVideoResolution.MD_RESOLUTION; // 限制视频分辨率为360p
      
      var options = JitsiMeetingOptions()
        ..room = "myroom" // 必填,空格会被删除
        ..serverURL = "https://someHost.com"
        ..subject = "Meeting with Gunschu"
        ..userDisplayName = "My Name"
        ..userEmail = "myemail@email.com"
        ..userAvatarURL = "https://someimageurl.com/image.jpg" // 或.png
        ..audioOnly = true
        ..audioMuted = true
        ..videoMuted = true
        ..featureFlag = featureFlag;

      await JitsiMeet.joinMeeting(options);
    } catch (error) {
      debugPrint("error: $error");
    }
  }

JitsiMeetingOptions

字段 是否必填 默认值 描述
room N/A 唯一房间名称,将附加到serverURL。有效字符:字母数字、破折号和下划线。
subject $room 会议名称,显示在会议顶部。如果为空,默认为房间名称,破折号和下划线替换为空格,首字母大写。
userDisplayName “Fellow Jitster” 用户的显示名称。
userEmail none 用户的电子邮件地址。
audioOnly false 开始会议时不使用视频。可以在会议中打开。
audioMuted false 开始会议时音频静音。可以在会议中取消静音。
videoMuted false 开始会议时视频静音。可以在会议中取消静音。
serverURL meet.jitsi.si 指定自己的托管服务器。必须是格式正确的绝对URL,如 https://someHost.com。默认为Jitsi Meet的服务器。
userAvatarURL N/A none 用户的头像URL。
token N/A none 用于认证的JWT令牌。
featureFlag 见下文 FeatureFlag类的对象,用于启用/禁用功能并设置Jitsi Meet SDK的视频分辨率。

FeatureFlag

特性标志允许您限制视频分辨率并启用/禁用Jitsi Meet SDK中提到的一些功能。如果您未向JitsiMeetingOptions提供任何标志,则将使用默认值。

我们正在使用来自Jitsi Meet存储库的官方标志列表: https://github.com/jitsi/jitsi-meet/blob/master/react/features/base/flags/constants.js

标志 默认 (Android) 默认 (iOS) 描述
addPeopleEnabled true true 启用蓝色按钮"Add people",当您单独通话时出现。需要启用邀请选项。
calendarEnabled true auto 启用日历集成。
callIntegrationEnabled true true 启用呼叫集成(iOS上的CallKit,Android上的ConnectionService)。 见下文
closeCaptionsEnabled true true 启用菜单中的字幕选项。
conferenceTimerEnabled true true 启用会议计时器。
chatEnabled true true 启用聊天(按钮和功能)。
inviteEnabled true true 启用菜单中的邀请选项。
iOSRecordingEnabled N/A false 在iOS上启用录制。
kickOutEnabled true true 启用视频缩略图中的踢出选项。
liveStreamingEnabled auto auto 启用菜单中的直播选项。
meetingNameEnabled true true 显示会议名称。
meetingPasswordEnabled true true 启用菜单中的会议密码选项(如果设置了会议密码,对话框仍会显示)。
pipEnabled auto auto 启用画中画模式。
raiseHandEnabled true true 启用菜单中的举手选项。
recordingEnabled auto N/A 启用菜单中的录制选项。
resoulution N/A N/A 设置本地和(最大)远程视频分辨率。覆盖服务器配置。接受的值有:LD_RESOLUTION(180p),MD_RESOLUTION(360p),SD_RESOLUTION(480p(SD)),HD_RESOLUTION(720p(HD))。
serverURLChangeEnabled true true 启用服务器URL更改。
tileViewEnabled true true 启用菜单中的平铺视图选项。
toolboxAlwaysVisible true true 工具箱(按钮和菜单)在通话期间始终可见(如果不是,则单击一次即可显示)。
videoShareButtonEnabled true true 启用视频共享按钮。
welcomePageEnabled false false 启用欢迎页面。“欢迎页面列出了最近的会议和日历预约,旨在被独立应用程序使用。”

关于呼叫集成的说明

Android上的呼叫集成(称为ConnectionService)由于造成许多问题,已在官方Jitsi Meet应用中禁用。你也应该禁用它以避免这些问题。

JitsiMeetingResponse

字段 类型 描述
isSuccess bool 成功指示器。
message String 成功消息或错误。
error dynamic 可选,仅在isSuccess为false时存在。错误对象。

监听会议事件

支持的事件

名称 描述
onConferenceWillJoin 会议正在加载。
onConferenceJoined 用户已加入会议。
onConferenceTerminated 用户已退出会议。
onPictureInPictureWillEnter 用户进入画中画模式。
onPictureInPictureTerminated 用户退出画中画模式。
onError 监听会议事件时发生错误。
每次会议事件

要按每次会议监听事件,请在joinMeeting中传递一个JitsiMeetingListener。当onConferenceTerminated事件触发时,监听器将自动移除。

await JitsiMeet.joinMeeting(options,
  listener: JitsiMeetingListener(onConferenceWillJoin: ({message}) {
    debugPrint("${options.room} will join with message: $message");
  }, onConferenceJoined: ({message}) {
    debugPrint("${options.room} joined with message: $message");
  }, onConferenceTerminated: ({message}) {
    debugPrint("${options.room} terminated with message: $message");
  }, onPictureInPictureWillEnter: ({message}) {
	debugPrint("${options.room} entered PIP mode with message: $message");
  }, onPictureInPictureTerminated: ({message}) {
	debugPrint("${options.room} exited PIP mode with message: $message");
  }));
全局会议事件

要监听全局会议事件,请简单地使用JitsiMeet.addListener(myListener)。可以使用JitsiMeet.removeListener(listener)JitsiMeet.removeAllListeners()来移除监听器。

[@override](/user/override)
void initState() {
  super.initState();
  JitsiMeet.addListener(JitsiMeetingListener(
    onConferenceWillJoin: _onConferenceWillJoin,
    onConferenceJoined: _onConferenceJoined,
    onConferenceTerminated: _onConferenceTerminated,
    onPictureInPictureWillEnter: _onPictureInPictureWillEnter,
    onPictureInPictureTerminated: _onPictureInPictureTerminated,
    onError: _onError));
}

[@override](/user/override)
void dispose() {
  super.dispose();
  JitsiMeet.removeAllListeners();
}

_onConferenceWillJoin({message}) {
  debugPrint("_onConferenceWillJoin broadcasted");
}

_onConferenceJoined({message}) {
  debugPrint("_onConferenceJoined broadcasted");
}

_onConferenceTerminated({message}) {
  debugPrint("_onConferenceTerminated broadcasted");
}

_onPictureInPictureWillEnter({message}) {
debugPrint("_onPictureInPictureWillEnter broadcasted with message: $message");
}

_onPictureInPictureTerminated({message}) {
debugPrint("_onPictureInPictureTerminated broadcasted with message: $message");
}

_onError(error) {
  debugPrint("_onError broadcasted");
}

程序化关闭会议

JitsiMeet.closeMeeting();

贡献

发送带有尽可能多信息的拉取请求,清楚地描述问题或功能。保持更改小,并针对一个问题一次进行。

功能请求

首先,此插件使用了Jitsi Meet的移动SDK,因此如果他们的SDK不支持某个功能,此插件可能也无法实现。检查Jitsi Meet是否支持您的请求。如果不支持,请向Jitsi Meet团队而不是这里提出功能请求。

如果新功能在Jitsi Meet的SDK中可用,但在本插件中不可用,或者新功能与SDK无关,请使用以下模板提交请求:

New Feature Request

使用场景:从用户或开发者的角度描述功能请求的使用场景。例如,“作为用户,我希望可以通过语音命令关闭会议。” 或 “作为开发者,我希望检测到用户眨眼。” 包括尽可能多的细节。

包括示例,如截图、用户体验设计、故事板或其他应用或代码示例,展示该功能的样子。

问题

在此处打开问题: https://github.com/gunschu/jitsi_meet/issues

使用以下模板:

平台:指定一个或两个:[iOS, Android] 
设备物理或模拟器:[Physical, Simulator]
设备型号:指定型号
设备操作系统版本:指定Android或iOS版本

Flutter Doctor:运行flutter doctor并粘贴结果:
--- flutter doctor 结果在这里 ---

重现步骤:详细分步说明如何重现:
1. 步骤1
2. 步骤2
...

错误日志:
--- 如果有任何,请粘贴错误日志 ---

示例代码

import 'dart:io';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

import 'package:jitsi_meeting_plus/jitsi_meet_plus.dart';
// import 'package:jitsi_meet/jitsi_meet.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(debugShowCheckedModeBanner: false, home: Meeting());
  }
}

class Meeting extends StatefulWidget {
  [@override](/user/override)
  _MeetingState createState() => _MeetingState();
}

class _MeetingState extends State<Meeting> {
  final serverText = TextEditingController();
  final roomText = TextEditingController(text: "plugintestroom");
  final subjectText = TextEditingController(text: "My Plugin Test Meeting");
  final nameText = TextEditingController(text: "Plugin Test User");
  final emailText = TextEditingController(text: "fake@email.com");
  final iosAppBarRGBAColor =
      TextEditingController(text: "#0080FF80"); //透明蓝
  bool? isAudioOnly = true;
  bool? isAudioMuted = true;
  bool? isVideoMuted = true;

  [@override](/user/override)
  void initState() {
    super.initState();
    JitsiMeetPlus.addListener(JitsiMeetingListener(
        // JitsiMeet.addListener(JitsiMeetingListener(
        onConferenceWillJoin: _onConferenceWillJoin,
        onConferenceJoined: _onConferenceJoined,
        onConferenceTerminated: _onConferenceTerminated,
        onPictureInPictureWillEnter: _onPictureInPictureWillEnter,
        onPictureInPictureTerminated: _onPictureInPictureTerminated,
        onError: _onError));
  }

  [@override](/user/override)
  void dispose() {
    super.dispose();
    JitsiMeetPlus.removeAllListeners();
    // JitsiMeet.removeAllListeners();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    double width = MediaQuery.of(context).size.width;
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('插件示例应用'),
        ),
        body: Container(
          padding: const EdgeInsets.symmetric(
            horizontal: 16.0,
          ),
          child: kIsWeb
              ? Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [
                    Container(
                      width: width * 0.30,
                      child: meetConfig(),
                    ),
                    Container(
                        width: width * 0.60,
                        child: Padding(
                          padding: const EdgeInsets.all(8.0),
                          child: Card(
                              color: Colors.white54,
                              child: SizedBox(
                                width: width * 0.60 * 0.70,
                                height: width * 0.60 * 0.70,
                                child: JitsiMeetConferencing(
                                  extraJS: [
                                    // extraJs setup example
                                    '<script>function echo(){console.log("echo!!!")};</script>',
                                    '<script src="https://code.jquery.com/jquery-3.5.1.slim.js" integrity="sha256-DrT5NfxfbHvMHux31Lkhxg42LY6of8TaYyK50jnxRnM=" crossorigin="anonymous"></script>'
                                  ],
                                ),
                              )),
                        ))
                  ],
                )
              : meetConfig(),
        ),
      ),
    );
  }

  Widget meetConfig() {
    return SingleChildScrollView(
      child: Column(
        children: <Widget>[
          SizedBox(
            height: 16.0,
          ),
          TextField(
            controller: serverText,
            decoration: InputDecoration(
                border: OutlineInputBorder(),
                labelText: "服务器URL",
                hintText: "提示:留空则使用meet.jitsi.si"),
          ),
          SizedBox(
            height: 14.0,
          ),
          TextField(
            controller: roomText,
            decoration: InputDecoration(
              border: OutlineInputBorder(),
              labelText: "房间",
            ),
          ),
          SizedBox(
            height: 14.0,
          ),
          TextField(
            controller: subjectText,
            decoration: InputDecoration(
              border: OutlineInputBorder(),
              labelText: "主题",
            ),
          ),
          SizedBox(
            height: 14.0,
          ),
          TextField(
            controller: nameText,
            decoration: InputDecoration(
              border: OutlineInputBorder(),
              labelText: "显示名称",
            ),
          ),
          SizedBox(
            height: 14.0,
          ),
          TextField(
            controller: emailText,
            decoration: InputDecoration(
              border: OutlineInputBorder(),
              labelText: "电子邮件",
            ),
          ),
          SizedBox(
            height: 14.0,
          ),
          TextField(
            controller: iosAppBarRGBAColor,
            decoration: InputDecoration(
                border: OutlineInputBorder(),
                labelText: "AppBar颜色(仅限iOS)",
                hintText: "提示:必须以十六进制RGBA格式输入"),
          ),
          SizedBox(
            height: 14.0,
          ),
          CheckboxListTile(
            title: Text("仅音频"),
            value: isAudioOnly,
            onChanged: _onAudioOnlyChanged,
          ),
          SizedBox(
            height: 14.0,
          ),
          CheckboxListTile(
            title: Text("音频静音"),
            value: isAudioMuted,
            onChanged: _onAudioMutedChanged,
          ),
          SizedBox(
            height: 14.0,
          ),
          CheckboxListTile(
            title: Text("视频静音"),
            value: isVideoMuted,
            onChanged: _onVideoMutedChanged,
          ),
          Divider(
            height: 48.0,
            thickness: 2.0,
          ),
          SizedBox(
            height: 64.0,
            width: double.maxFinite,
            child: ElevatedButton(
              onPressed: () {
                _joinMeeting();
              },
              child: Text(
                "加入会议",
                style: TextStyle(color: Colors.white),
              ),
              style: ButtonStyle(
                  backgroundColor:
                      MaterialStateColor.resolveWith((states) => Colors.blue)),
            ),
          ),
          SizedBox(
            height: 48.0,
          ),
        ],
      ),
    );
  }

  _onAudioOnlyChanged(bool? value) {
    setState(() {
      isAudioOnly = value;
    });
  }

  _onAudioMutedChanged(bool? value) {
    setState(() {
      isAudioMuted = value;
    });
  }

  _onVideoMutedChanged(bool? value) {
    setState(() {
      isVideoMuted = value;
    });
  }

  _joinMeeting() async {
    String? serverUrl = serverText.text.trim().isEmpty ? null : serverText.text;

    // 启用或禁用任何功能标志
    // 如果未提供功能标志,将使用默认值
    // 完整的功能标志列表(及其默认值)可在README中找到
    Map<FeatureFlagEnum, bool> featureFlags = {
      FeatureFlagEnum.WELCOME_PAGE_ENABLED: false,
      FeatureFlagEnum.OVERFLOW_MENU_ENABLED: false,
      FeatureFlagEnum.PIP_ENABLED: true,
    };
    if (!kIsWeb) {
      // 这里是一个示例,为每个平台禁用功能
      if (Platform.isAndroid) {
        // 禁用Android上的ConnectionService以避免问题(参阅README)
        featureFlags[FeatureFlagEnum.CALL_INTEGRATION_ENABLED] = false;
      } else if (Platform.isIOS) {
        // 禁用iOS上的画中画,因为它看起来很奇怪
        featureFlags[FeatureFlagEnum.PIP_ENABLED] = false;
      }
    }
    // 定义会议选项
    var options = JitsiMeetingOptions(room: roomText.text)
      ..serverURL = serverUrl
      ..subject = subjectText.text
      ..userDisplayName = nameText.text
      ..userEmail = emailText.text
      ..iosAppBarRGBAColor = iosAppBarRGBAColor.text
      ..audioOnly = isAudioOnly
      ..audioMuted = isAudioMuted
      ..videoMuted = isVideoMuted
      ..featureFlags.addAll(featureFlags)
      ..webOptions = {
        "roomName": roomText.text,
        "width": "100%",
        "height": "100%",
        "enableWelcomePage": false,
        "chromeExtensionBanner": null,
        "userInfo": {"displayName": nameText.text}
      };

    debugPrint("JitsiMeetingOptions: $options");
    await JitsiMeetPlus.joinMeeting(
      // await JitsiMeet.joinMeeting(
      options,
      listener: JitsiMeetingListener(
          onConferenceWillJoin: _onConferenceWillJoin,
          onConferenceJoined: _onConferenceJoined,
          onConferenceTerminated: _onConferenceTerminated,
          onPictureInPictureWillEnter: _onPictureInPictureWillEnter,
          onPictureInPictureTerminated: _onPictureInPictureTerminated,
          genericListeners: [
            JitsiGenericListener(
                eventName: 'readyToClose',
                callback: (dynamic message) {
                  debugPrint("readyToClose callback");
                }),
          ]),
    );
  }

  void _onConferenceWillJoin(message) {
    debugPrint("_onConferenceWillJoin broadcasted with message: $message");
  }

  void _onConferenceJoined(message) {
    debugPrint("_onConferenceJoined broadcasted with message: $message");
  }

  void _onConferenceTerminated(message) {
    debugPrint("_onConferenceTerminated broadcasted with message: $message");
  }

  _onError(error) {
    debugPrint("_onError broadcasted: $error");
  }

  _onPictureInPictureWillEnter(Map message) {
    debugPrint(
        "_onPictureInPictureWillEnter broadcasted with message: $message");
  }

  _onPictureInPictureTerminated(Map message) {
    debugPrint(
        "_onPictureInPictureTerminated broadcasted with message: $message");
  }
}

更多关于Flutter视频会议插件jitsi_meeting_plus的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter视频会议插件jitsi_meeting_plus的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何在Flutter项目中使用jitsi_meeting_plus插件来集成Jitsi Meet视频会议功能的代码示例。这个插件允许你直接在Flutter应用中嵌入Jitsi Meet视频会议界面。

首先,确保你的Flutter项目已经设置好,并且你已经添加了jitsi_meeting_plus依赖到你的pubspec.yaml文件中:

dependencies:
  flutter:
    sdk: flutter
  jitsi_meeting_plus: ^最新版本号  # 请替换为当前最新版本号

然后运行flutter pub get来安装依赖。

接下来,在你的Flutter项目中,你可以按照以下步骤使用jitsi_meeting_plus插件:

  1. 导入插件

在你的Dart文件中导入jitsi_meeting_plus插件:

import 'package:jitsi_meeting_plus/jitsi_meeting_plus.dart';
  1. 配置和启动Jitsi Meet界面

你可以通过创建一个函数来配置并启动Jitsi Meet会议。下面是一个简单的示例:

import 'package:flutter/material.dart';
import 'package:jitsi_meeting_plus/jitsi_meeting_plus.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Jitsi Meet Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Jitsi Meet Example'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () => _startJitsiMeeting(),
          child: Text('Start Jitsi Meeting'),
        ),
      ),
    );
  }

  Future<void> _startJitsiMeeting() async {
    // Jitsi Meet会议的配置选项
    final options = JitsiMeetingOptions(
      room: '你的会议室链接或名称', // 替换为你的Jitsi服务器和房间名
      url: 'https://meet.jit.si', // Jitsi服务器的URL,默认为meet.jit.si
      userInfo: {
        'displayName': '用户名', // 可选,用户的显示名称
        'email': '用户邮箱', // 可选,用户的邮箱
      },
      audioOnly: false, // 是否仅音频
      subject: '会议主题', // 可选,会议主题
      password: '会议密码', // 可选,如果会议设置了密码
      // 更多配置选项可以参考jitsi_meeting_plus的文档
    );

    // 启动Jitsi Meet会议
    await JitsiMeetingPlus.joinMeeting(options);
  }
}

在这个示例中,当用户点击按钮时,_startJitsiMeeting函数会被调用,它会使用提供的配置选项启动Jitsi Meet会议。

请注意,room参数是你的Jitsi会议室的链接或名称,url参数是你的Jitsi服务器的URL(默认为https://meet.jit.si)。你还可以根据需要配置其他选项,如用户的显示名称、邮箱、是否仅音频、会议主题和密码等。

这个示例提供了一个基本的框架,你可以根据自己的需求进一步定制和扩展功能。更多详细信息和配置选项,请参考jitsi_meeting_plus插件的官方文档。

回到顶部