How To Add Video Chat/Calling Feature To Your Flutter Application
Forget about emails, texts, and instant messages — the last few years have shown us that video calling is the preferred way people want to connect moving forward!
Adding video chat and calling to your Flutter application is a great way to improve user engagement and keep them coming back for more. And Dyte is one of the best Video SDKs that can help you do that.
Steps To Build Your Video Calling App In Flutter
Building a video calling app in Flutter involves installing the flutter package from Pub, including Dyte’s widget and more, but let's start with the prerequisites.
Before You Begin
Be sure to follow these requirements in the order they are listed here.
1. Create a Dyte Account
The first step is to sign up for a Dyte account. Once you've created your account, you'll be able to access the Dyte Dashboard, where you can find the API key that will be used to authenticate your app with the Dyte platform.
2. Install Flutter SDK
Now that you have a token, it's time to install the Flutter SDK. The Flutter SDK is a toolkit for building cross-platform mobile apps. It's free and open source, and it comes with everything you need to get started building your app. To install the Flutter SDK, follow the instructions on the official website.
3. Install Flutter On Your Device
Now that you have everything set up, it's time to run your app on your device!
1. Connect your device to your computer using a USB cable.
2. Open a terminal window.
3. Navigate to the directory where your app is located and type flutter run .
This will compile and run your app on your device. You should see a screen like this:
1. Install The Flutter Package From Pub
Upon meeting the requirements, install the Flutter package from Pub using the below code.
flutter pub add dyte_client
Android
Prerequisite
Check /android/app/build.gradle
to ensure your Flutter Android SDK version is 21.
Note
There are no additional steps required for debug builds, as the instructions below are only for release builds.
1. Change android/gradle.properties to include the following
android.enableDexingArtifactTransform.desugaring=false
2. Create / insert into the android/app/proguard-rules.pro
-keep class org.webrtc.** { *; }
-dontwarn org.chromium.build.BuildHooksAndroid
3. In the android/app/build.gradle, add the following line to the release configuration to import the proguard configuration
buildTypes {
release {
...
...
...
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
iOS
Prerequisite
Ensure that your Apple Silicon based Mac runs Xcode using Rosetta.
MINIMUM IOS VERSION 12.0
For iOS SDK, we support at least OS version 12.0.
1. Verify that you have iOS 12 set up in your `podfile`
platform :ios, '12.0'
2. Enter fonts and permissions in info.plist
<key>UIAppFonts</key>
<array>
<string>MaterialCommunityIcons.ttf</string>
<string>MaterialIcons.ttf</string>
</array>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>We will use your Bluetooth to access your Bluetooth headphones.</string>
<key>NSBluetoothAlwaysUsageDescription</key>
<string>We will use your Bluetooth to access your Bluetooth headphones.</string>
<key>NSCameraUsageDescription</key>
<string>For people to see you during meetings, we need access to your camera.</string>
<key>NSMicrophoneUsageDescription</key>
<string>For people to hear you during meetings, we need access to your microphone.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>For people to share, we need access to your photos.</string>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
3. You should have an entry in your Podfile that declares that your platform is 11.0 or higher and that BITCODE is disabled.
<key>UIAppFonts</key>
<array>
<string>MaterialCommunityIcons.ttf</string>
<string>MaterialIcons.ttf</string>
</array>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>We will use your Bluetooth to access your Bluetooth headphones.</string>
<key>NSBluetoothAlwaysUsageDescription</key>
<string>We will use your Bluetooth to access your Bluetooth headphones.</string>
<key>NSCameraUsageDescription</key>
<string>For people to see you during meetings, we need access to your camera.</string>
<key>NSMicrophoneUsageDescription</key>
<string>For people to hear you during meetings, we need access to your microphone.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>For people to share, we need access to your photos.</string>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
post_install do |installer|
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['ENABLE_BITCODE'] = 'NO'
end
end
end
2. Include Dyte's Flutter Widget in Your App
After installing the Flutter Package From Pub, you can include the DyteMeeting in your app. It is a Flutter widget for displaying the Dyte Meeting UI. Let's look at the properties and how they are used.
Configure The Meeting Connection
In order for the client to connect to the correct meeting, you need to pass DyteMeeting, authToken, and roomName.
DyteMeeting, authToken, and roomName.
SizedBox(
width: <width>,
height: <height>,
child: DyteMeeting(
roomName: "<roomName>",
authToken: "<authToken>",
)
)
Get Meeting Instance On Successful Creation
In order to get a reference to a newly created meeting instance, you must pass an onInit property to DyteMeeting. The onInit function has one parameter of type DyteMeetingHandler and is an async callback function. You can customize the DyteMeetingHandler reference to take further actions for meeting customizations.
SizedBox(
width: <width>,
height: <height>,
child: DyteMeeting(
roomName: "<roomName>",
authToken: "<authToken>",
onInit: (DyteMeetingHandler meeting) async {
// your handler
},
)
)
3. Customize the Meeting UI
Now comes the customization part that decides the overall theme of the project. You can override the default values for these options at the client end based on specific use cases or events. The default values for these options are taken from the authToken generation preset.
Provide the uiConfigOptions as a parameter to the updateUIConfig method on the meeting instance.
meeting.updateUIConfig(uiConfigOptions);
Set Your Logo in the Meeting Room
Your brand or organization's logo can be displayed in the meeting room with the following code:
meeting.updateUIConfig({ 'logo': '<logoUrlString>' });
Change The Color Scheme To Your Brand / Theme
Your brand and theme can be reflected in the color scheme of the meeting. Using Dyte, you can specify up to four colors.
- Primary: The color and main elements of the participant name box
- Secondary: The color of control bars, buttons, and hovers
- TextPrimary: color of text element
- VideoBackground: The background color when there is no video playing
Below is an example showing the default values. If all colors are not specified, this feature will not work.
meeting.updateUIConfig({
'colors': {
'primary': '#2160FD',
'secondary': '#262626',
'textPrimary': '#EEEEEE',
'videoBackground': '#1A1A1A'
}
});
Adjust the Meeting Size to a Custom Container
By default, Dyte meeting views take up the entire screen. The dimensions section allows you to specify the width and height of a meeting in pixels (px in CSS) if the size of the meeting needs to be adjusted for a particular container. It is necessary to specify both for this feature to work.
meeting.updateUIConfig({
'dimensions': {
'width': 400,
'height': 800
}
});
ke The Meeting Fit Your Container Size (Dynamic)
When the value is set to fillParent, the meeting will fit within the boundaries of its parent container or div.
meeting.updateUIConfig({
'dimensions': {
'mode': 'fillParent'
}
});
Prerequisite
Dimensions should either be width and height or mode, not both.
Hide The Bottom Control Bar
Setting controlBar to false in config will hide the bottom control bar. Control bars are visible by default since the value is true.
meeting.updateUIConfig({ 'controlBar': true });
Hide Individual Controls From The Bottom Control Bar
If you set the respective options to false in the configuration, you can hide individual controls from the bottom control bar. Default values for all controls are true, making all the controls visible.
meeting.updateUIConfig({
'controlBarElements': {
'fullscreen': true,
'share': true,
'screenShare': true,
'layout': true,
'chat': true,
'polls': true,
'participants': true,
'plugins': true
}
});
Hide The Header Bar
In the configuration, set header to false to hide the header bar. It is set to true by default, allowing the header to be seen.
meeting.updateUIConfig({ 'header': true });
Hide Individual Controls From The Header Bar
The header bar can be hidden by setting the options for individual elements to false in the config. All elements are visible by default when the value is true.
meeting.updateUIConfig({
'headerElements': {
'logo': true,
'title': true,
'participantCount': true,
'clock': true
}
});
4. Advanced Usage
This section covers advanced topics such as how to preview the screen, dynamic codec switching, etc.
Turn On The Setup / Preview Screen
Before getting into the meeting, participants see a screen that allows them to set up their audio and video. Turn it on by setting showSetupScreen to true in meetingConfig (false by default).
SizedBox(
width: <width>,
height: <height>,
child: DyteMeeting(
roomName: "<roomName>",
authToken: "<authToken>",
onInit: (DyteMeetingHandler meeting) async {
// your handler
},
showSetupScreen: true,
)
)
Dynamic Codec Switching
When participants' video codecs are not supported, Dyte switches to H264/VP8 by default. The VP9 codec is superior, but it is not supported by all browsers. With autoTune set to false in meetingConfig, Dyte will only use VP8 for all participants (the default is true).
SizedBox(
width: <width>,
height: <height>,
child: DyteMeeting(
roomName: "<roomName>",
authToken: "<authToken>",
onInit: (DyteMeetingHandler meeting) async {
// your handler
},
autoTune: false,
)
)
Control The Meeting, And Take Meeting & Participant Actions
You interact with the meeting using the DyteMeetingHandler instance (referenced above as meeting). In addition to taking action on the meeting, you can also take action on the participants. Custom controls can also be created in such a way that they can be configured to interact with the meeting in specific ways that allow you to communicate with other participants through events and messages. DyteMeetingHandler's full reference can be found here.
Replace The Meeting Control Buttons With Your Own Buttons
There are times when you want to keep things simple for your participants. If that's the case, Dyte’s got what you need! Dyte offers customers a wide range or customizable button designs so they can easily control everything about their meeting without any fuss from us.
Our control bar would be the first thing to go in such a scenario.
meeting.updateUIConfig({ controlBar: false });
Following are the key functions of a meeting you can call/invoke. Your own buttons can use these functions inside onClick handlers.
Mic Control
Turning the microphone off
meeting.self.disableAudio();
Turning the microphone on
meeting.self.enableAudio();
Camera Control
Turning the camera off
meeting.self.disableVideo();
Turning the camera on
meeting.self.enableVideo();
Leave Meeting
Leaving the meeting
meeting.leaveRoom();
Get a List Of All Participants In The Meeting
Using the participants
property of the meeting, you can find out who is in the meeting.
var participantList = meeting.participants;
The participantList
is an array of DyteParticipant instances, which can be directly used as types if you prefer TypeScript bindings. The current participant will be represented by an element of type DyteSelfParticipant.
Controlling Individual Participants And Actions
You can control participant actions and certain UI elements with Dyte client SDK methods and properties. Participants can be affected by such actions as well as other participants (e.g., a host with privileged permissions may wish to control other participants' video). The following section describes all the possible properties and actions.
Get Participant List
For a list of meeting participants, run meeting.participants
: it returns List<DyteParticipant>
whose members are DyteParticipants
.
Participant Info And Actions
Following the above approach, you can iterate over that array and get certain participant information.
In the next section, we'll take a look at the iterator in the next section.
meeting.participants.forEach((p) => {
// participant specific code goes here
});
Peer Id
Fetch a unique ID for each participant. As soon as a participant joins the meeting, Dyte produces this ID. A participant ID can be used to send custom messages within Dyte.
INFO
The peer ID of the same participant, even if he or she rejoins the meeting using the same authentication token, will be refreshed if the web page / app is refreshed, or if the connection drops.
var peerID = p.id;
The peerID value is set to a UUID string.
Client-Specific ID
You can obtain the client-specific ID by calling the add participant API. This identifier can help you find the participant information in your system if you decide to expose custom controls or build business logic based on it.
var clientSpecificID = p.clientSpecificId;
Participant Name
You can get a participant's name using the API call add participant. If enabled, this name may have been changed by the participant.
var name = p.name;
Participant Thumbnail Photo / Avatar
In the API call for adding participants, you can get the participant's photo.
var name = p.picture;
Check If Participant's Audio Is On
In order to verify that the audio of a participant is active (mic is on), the user can use
var audio = p.audioEnabled;
A boolean value is set to audio to indicate whether or not the mic is on.
Check If Participant's Video Is On
To determine whether the camera of a participant is on (video is on), perform the following:
var video = p.videoEnabled;
This setting specifies whether the camera is on or off by setting the value of video to a boolean.
Check If The Participant Is Pinned To The Grid
To You can use the meeting grid to check if a participant's video has been pinned; either by a host, a user, or a preset;
var pinned = p.isPinned;
It specifies whether the video is pinned or not by setting the value of pinned to boolean.
5. Events
The Dyte SDK also emits a variety of events related to meeting events and state changes for ease of integration into modern workflows. In real-time, your app can react to meeting changes based on events. A Meeting instance can subscribe to the following events.
Connected To The Meeting
When a participant joins a meeting but does not produce or consume content streams, this event occurs. Essentially, this is about successfully connecting to the meeting.
meeting.events.on('meetingConnected', this, (ev, cont) {
});
Joined The Meeting
When the participant joins the meeting, this event will be triggered, and the participant will be able to start producing and consuming content.
meeting.events.on('meetingJoin', this, (ev, cont) {
});
Disconnected From The Meeting
If a participant disconnects from a meeting for any reason, this event will be triggered. Participants might have disconnected from the network, exited the meeting manually, or closed the meeting tab / browser / app. There are many reasons why this might happen.
meeting.events.on('meetingDisconnected', this, (ev, cont) {
});
End Of The Meeting
It is triggered by either the organization (as an administrative function) or the host when the meeting has ended. This will result in all participants being kicked out of the session, and you can either ask for feedback or redirect them to another exercise.
meeting.events.on('meetingEnd', this, (ev, cont) {
});
Input Media Devices Get Connected To The Meeting
As soon as the participant's local media input devices (camera and microphone) are set up and engaged for the first time, this event will be triggered. Managing the starting state of a participant's audio or video requires this event since the media device state can only be toggled after the device is connected.
meeting.events.on('localMediaConnected', null, (a, b) {
});
Another Participant Joins The Meeting
Whenever another participant enters the meeting, this event will be triggered. "Join" refers to the same event as meetingJoined; therefore, when it triggers for one participant, it triggers for all other participants.
import 'package:dyte_client/dyteParticipant.dart';
meeting.events.on('participantJoin', this, (ev, cont) {
DyteParticipant p = ev.eventData as DyteParticipant;
});
Another Participant Leaves The Meeting
A disconnect event is triggered when another participant leaves the meeting. 'Disconnect' in this context means the same thing as disconnect events: it triggers for all participants when it occurs for one.
import 'package:dyte_client/dyteParticipant.dart';
meeting.events.on('participantLeave', this, (ev, cont) {
DyteParticipant p = ev.eventData as DyteParticipant;
});
Quickstart Your Video Calling Of Flutter App With Dyte
Now that you've met the requirements and grasped the basics, It's time to finish up the process and get your flutter app integrated with video calling service. Using Dyte's backend APIs, retrieve the meeting room name and attendee's authToken, and send them to the DyteMeeting widget.
1. Prepare the package for import.
import 'package:dyte_client/dyte.dart';
import 'package:dyte_client/dyteMeeting.dart';
2. Provide the DyteMeeting widget with relevant information.
SizedBox(
width: <width>,
height: <height>,
child: DyteMeeting(
roomName: "<roomName>",
authToken: "<authToken>",
onInit: (DyteMeetingHandler meeting) async {
// your handler
},
)
)
The parent widget only needs a maxHeight and maxWidth, and the constraining widget can be any widget (not limited to SizedBox).
Here is an example of code that allows a full-screen meeting.
import 'package:flutter/material.dart';
import 'package:dyte_client/dyte.dart';
void main() {
runApp(MaterialApp(home:MyApp()));
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
// get the page height, width
double width = MediaQuery.of(context).size.width;
double height = MediaQuery.of(context).size.height;
return Scaffold(
body: Row(
children: <Widget>[
SizedBox(
width: width,
height: height,
child: DyteMeeting(
roomName: "<roomName>",
authToken: "<authToken>",
onInit: (DyteMeetingHandler meeting) async {
var self = await meeting.self;
},
)
)
],
),
);
}
}
Bottomline!
Video calling is the way of the future. It's a great addition to any app, and with Flutter, it's easy to add. When you consider all the benefits that come with adding video calling to an app, there is no reason not to add it. And if you want to add video calling to your Flutter application, there's no better choice than Dyte.
It only takes a few code lines to give your users the ability to connect with each other in real-time no matter where they are. Our platform is feature-rich, customizable, and backed by dedicated support experts. Contact us today, and let's get your product built faster.
You can find the source code of the Flutter Sample App discussed in this blog post on our GitHub repo here.
If you haven't heard of Dyte yet, go to https://dyte.io to learn how our SDKs and libraries are revolutionizing live video and voice calling experience. Don't just take our word for it; try it for yourself!
Dyte offers free 10,000 minutes every month to get you started quickly.If you have any questions or simply want to chat with us, please contact us through support or visit our developer community forum. Looking forward to it!