Meet Hour Flutter SDK

Meet Hour Plugin for Flutter. Supports Android and iOS platforms.

"Meet Hour is 100% free video conference solution with End to End Encrypted and many other features such as lobby mode, Donor box & Click&Pledge Connect for fundraising, Video call recording, Youtube Live Stream etc."

Example Project is here -

Pub dev -

  meet_hour: '>=5.0.7'

MeetHour SDK Implementation - Steps

  1. SDK Examples Link -
  2. API Documentation Link -

Steps to Integrate:

  1. Signup for Meet Hour ( and signup for Developer or Higher plan. Currently we offer 28 days free trial.
  2. Once you signup for developer plan, and go to our Dashboard - ( and tap on "Developers" menu.
  3. Now copy and Client ID & Client Secret and keep it handy with you.
  4. Go to our API documentation and hit Login API to get oAuth Access Token - (
  5. Once you get an access token, you can access any our API. Now you first thing you have to do is create a contact in our system as soon as user signup in your platform using this API ( This will give you unique contact_id of that user. You require this id when you schedule a meeting below.
  6. Later go to Schedule Meeting API -> Pass all the parameters needed to generate a new meetings - (
  7. Once the meeting is genereate, in order to join a meeting you require to Generate JWT Token using this API ( and pass it to the conference URL via MT Parameter -

Table of Contents



  • Note: Example compilable with XCode 12.2 & Flutter 1.22.4.


Ensure in your Podfile you have an entry like below declaring platform of 11.0 or above and disable BITCODE.

platform :ios, '12.1'


post_install do |installer|
  installer.pods_project.targets.each do |target|
      target.build_configurations.each do |config|
        config.build_settings['ENABLE_BITCODE'] = 'NO'
        config.build_settings["EXCLUDED_ARCHS[sdk=iphonesimulator*]"] = "arm64"


Add NSCameraUsageDescription and NSMicrophoneUsageDescription to your Info.plist.

<string>$(PRODUCT_NAME) MyApp needs access to your camera for meetings.</string>
<string>$(PRODUCT_NAME) MyApp needs access to your microphone for meetings.</string>



Set dependencies of build tools gradle to minimum 3.6.3:

dependencies {
    classpath '' <!-- Upgrade this -->
    classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"

Set distribution gradle wrapper to minimum 5.6.4.

distributionUrl=https\:// <!-- Upgrade this -->


Meet Hour's SDK AndroidManifest.xml will conflict with your project, namely the application:label field. To counter that, go into android/app/src/main/AndroidManifest.xml and add the tools library and tools:replace="android:label" to the application tag.

<manifest xmlns:android=""
    xmlns:tools=""> <!-- Add this -->
        android:label="My Application"

Minimum SDK Version 23

Update your minimum sdk version to 23 in android/app/build.gradle

defaultConfig {
    applicationId ""
    minSdkVersion 23 //Required for MeetHour
    targetSdkVersion 28
    versionCode flutterVersionCode.toInteger()
    versionName flutterVersionName


MeetHour's SDK enables proguard, but without a file, your release apk build will be missing the Flutter Wrapper as well as react-native code. In your Flutter project's android/app/build.gradle file, add proguard support

buildTypes {
    release {
        // TODO: Add your own signing config for the release build.
        // Signing with the debug keys for now, so `flutter run --release` works.
        signingConfig signingConfigs.debug
        // Add below 3 lines for proguard
        minifyEnabled true
        useProguard true
        proguardFiles getDefaultProguardFile('proguard-android.txt'), ''

Then add a file in the same directory called See the example app's file to know what to paste in.

If you do not create the file, then your app will crash when you try to join a meeting or the meeting screen tries to open but closes immediately. You will see one of the below errors in logcat.

## App crashes ##
java.lang.RuntimeException: Parcel android.os.Parcel@8530c57: Unmarshalling unknown type code 7536745 at offset 104
    at android.os.Parcel.readValue(
    at android.os.Parcel.readSparseArrayInternal(
    at android.os.Parcel.readSparseArray(
## Meeting won't open and you go to previous screen ##
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
W/unknown:ViewManagerPropertyUpdater: Could not find generated setter for class

Join A Meeting

_joinMeeting() async {
    try {
	  FeatureFlag featureFlag = FeatureFlag();
	  featureFlag.welcomePageEnabled = false;
	  featureFlag.resolution = FeatureFlagVideoResolution.MD_RESOLUTION; // Limit video resolution to 360p
      var options = MeetHourMeetingOptions() = "TestRoom" // Required, spaces will be trimmed
        ..serverURL = ""
        ..subject = "Meeting with John"
        ..userDisplayName = "John Delise"
        ..userEmail = ""
        ..userAvatarURL = "" // or .png
        ..audioOnly = true
        ..audioMuted = true
        ..videoMuted = true
        ..featureFlag = featureFlag;

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


roomYesN/AUnique room name that will be appended to serverURL. Valid characters: alphanumeric, dashes, and underscores.
subjectNo$roomMeeting name displayed at the top of the meeting. If null, defaults to room name where dashes and underscores are replaced with spaces and first characters are capitalized.
userDisplayNameNo"Guest"User's display name.
userEmailNononeUser's email address.
audioOnlyNofalseStart meeting without video. Can be turned on in meeting.
audioMutedNofalseStart meeting with audio muted. Can be turned on in meeting.
videoMutedNofalseStart meeting with video muted. Can be turned on in meeting.
serverURLNomeethour.ioSpecify your own hosted server. Must be a valid absolute URL of the format <scheme>://<host>[/path], i.e. Defaults to Meet Hour's servers.
userAvatarURLN/AnoneUser's avatar URL.
tokenN/AnoneJWT token used for authentication.
featureFlagNosee belowObject of FeatureFlag class used to enable/disable features and set video resolution of Meet Hour SDK.


Feature flag allows you to limit video resolution and enable/disable few features of Meet Hour SDK mentioned in the list below.
If you don't provide any flag to MeetHourMeetingOptions, default values will be used.

FlagDefault (Android)Default (iOS)Description
addPeopleEnabledtruetrueEnable the blue button "Add people", show up when you are alone in a call. Required for flag inviteEnabled to work.
calendarEnabledtrueautoEnable calendar integration.
callIntegrationEnabledtruetrueEnable call integration (CallKit on iOS, ConnectionService on Android). SEE REMARK BELOW
closeCaptionsEnabledtruetrueEnable close captions (subtitles) option in menu.
conferenceTimerEnabledtruetrueEnable conference timer.
chatEnabledtruetrueEnable chat (button and feature).
inviteEnabledtruetrueEnable invite option in menu.
iOSRecordingEnabledN/AfalseEnable recording in iOS.
kickOutEnabledtruetrueEnable kick-out option in video thumb of participants.
liveStreamingEnabledautoautoEnable live-streaming option in menu.
meetingNameEnabledtruetrueDisplay meeting name.
meetingPasswordEnabledtruetrueDisplay meeting password option in menu (if a meeting has a password set, the dialog will still show up).
pipEnabledautoautoEnable Picture-in-Picture mode.
raiseHandEnabledtruetrueEnable raise hand option in menu.
recordingEnabledautoN/AEnable recording option in menu.
resoulutionN/AN/ASet local and (maximum) remote video resolution. Overrides server configuration. Accepted values are: LD_RESOLUTION for 180p, MD_RESOLUTION for 360p, SD_RESOLUTION for 480p(SD), HD_RESOLUTION for 720p(HD) .
serverURLChangeEnabledtruetrueEnable server URL change.
tileViewEnabledtruetrueEnable tile view option in menu.
toolboxAlwaysVisibletruetrueToolbox (buttons and menus) always visible during call (if not, a single tap displays it).
videoShareButtonEnabledtruetrueEnable video share button.
welcomePageEnabledfalsefalseEnable welcome page. "The welcome page lists recent meetings and calendar appointments and it's meant to be used by standalone applications."


isSuccessboolSuccess indicator.
messageStringSuccess message or error as a String.
errordynamicOptional, only exists if isSuccess is false. The error object.

Listening to Meeting Events

Events supported

onConferenceWillJoinMeeting is loading.
onConferenceJoinedUser has joined meeting.
onConferenceTerminatedUser has exited the conference.
onPictureInPictureWillEnterUser entered PIP mode.
onPictureInPictureTerminatedUser exited PIP mode.
onErrorError has occurred with listening to meeting events.

Per Meeting Events

To listen to meeting events per meeting, pass in a MeetHourMeetingListener in joinMeeting. The listener will automatically be removed when an
onConferenceTerminated event is fired.

await MeetHour.joinMeeting(options,
  listener: MeetHourMeetingListener(onConferenceWillJoin: ({message}) {
    debugPrint("${} will join with message: $message");
  }, onConferenceJoined: ({message}) {
    debugPrint("${} joined with message: $message");
  }, onConferenceTerminated: ({message}) {
    debugPrint("${} terminated with message: $message");
  }, onPictureInPictureWillEnter: ({message}) {
	debugPrint("${} entered PIP mode with message: $message");
  }, onPictureInPictureTerminated: ({message}) {
	debugPrint("${} exited PIP mode with message: $message");

Global Meeting Events

To listen to global meeting events, simply add a MeetHourListener with
MeetHour.addListener(myListener). You can remove listeners using
MeetHour.removeListener(listener) or MeetHour.removeAllListeners().

void initState() {
    onConferenceWillJoin: _onConferenceWillJoin,
    onConferenceJoined: _onConferenceJoined,
    onConferenceTerminated: _onConferenceTerminated,
    onPictureInPictureWillEnter: _onPictureInPictureWillEnter,
    onPictureInPictureTerminated: _onPictureInPictureTerminated,
    onError: _onError));

void dispose() {

_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");

Closing a Meeting Programmatically



Send a pull request with as much information as possible clearly describing the issue or feature. Keep changes small and for one issue at a time.