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 的入口点,用于启动会议屏幕、发送和接收所有事件。

  1. 构造函数

    MoiMeet()
    
  2. 加入会议

    join(MoiMeetConferenceOptions options, [MoiMeetEventListener? listener])
    

    参数:

    • options:会议选项。
    • listener:事件监听器,用于接收由原生 SDK 触发的事件。
  3. 挂断

    hangUp()
    
  4. 设置音频静音

    setAudioMuted(bool muted)
    
  5. 设置视频静音

    setVideoMuted(bool muted)
    
  6. 发送数据通道消息

    sendEndpointTextMessage({String? to, required String message})
    
  7. 切换屏幕共享

    toggleScreenShare(bool enabled)
    
  8. 打开聊天对话框

    openChat([String? to])
    
  9. 发送聊天消息

    sendChatMessage({String? to, required String message})
    
  10. 关闭聊天对话框

    closeChat()
    
  11. 获取参与者信息

    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 事件的监听器类。

  1. 会议已加入

    conferenceJoined(String url)
    
  2. 会议终止

    conferenceTerminated(String url, Object? error)
    
  3. 即将加入会议

    conferenceWillJoin(String url)
    
  4. 参与者已加入

    participantJoined(String? email, String? name, String? role, String? participantId)
    
  5. 参与者已离开

    participantLeft(String? participantId)
    
  6. 音频静音状态改变

    audioMutedChanged(bool muted)
    
  7. 视频静音状态改变

    videoMutedChanged(bool muted)
    
  8. 接收到文本消息

    endpointTextMessageReceived(String senderId, String message)
    
  9. 屏幕共享状态改变

    screenShareToggled(String participantId, bool sharing)
    
  10. 接收到聊天消息

    chatMessageReceived(String senderId, String message, bool isPrivate, String? timestamp)
    
  11. 聊天对话框打开或关闭

    chatToggled(bool isOpen)
    
  12. 获取参与者信息

    participantsInfoRetrieved(String participantsInfo)
    
  13. 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

1 回复

更多关于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}');
    }
    // 处理其他事件类型...
  });
}

注意事项

  1. 错误处理:确保在生产代码中妥善处理各种可能的错误,例如网络错误、认证失败等。
  2. UI优化:根据实际需求优化UI,例如添加加载指示器、错误提示等。
  3. 权限管理:确保应用有适当的权限,例如相机和麦克风权限。

这个示例提供了一个基本的框架,你可能需要根据moi_meet_flutter_sdk的具体文档和功能需求进行进一步的定制和扩展。

回到顶部