← Back to list

Video Call App with Flutter and Agora SDK

Building a video call application might sound like a daunting task involving complex WebRTC configurations and server-side logic. However…

Dheeraj Prajapat · 2026-01-10 10:32 · 0 claps · 3.0 min read
#flutter #agora #video-call #getting-started
Open on Medium ↗
Wiki topics: 📱 · Mobile Development

Video Call App with Flutter and Agora SDK

Building a video call application might sound like a daunting task involving complex WebRTC configurations and server-side logic. However, with Flutter and the Agora SDK, you can get a fully functional video calling app up and running in just a few simple steps.

Getting started

You need to create an agora account before integrating. An Agora Project with an App ID and a temporary Token.

After logging, Create a new project and copy your App ID.

Once create a project after that click configure and generate temporary token.

Enter channel name and click generate button.

The Channel Name and Token together determine which users can join the same video call.

Create a New Flutter Project - Once your Agora setup is complete, create a new Flutter project

Add Required Dependencies - Open your pubspec.yaml file and add the following packages

dependencies:
  flutter:
    sdk: flutter
  agora_rtc_engine: ^6.5.3
  permission_handler: ^12.0.1
  1. agora_rtc_engine: The official Agora SDK for Flutter.
  2. permission_handler: To handle camera and microphone permissions at runtime.

Platform Configuration

To access the camera and microphone, we need to configure native platform permissions.

Android

Open android/app/src/main/AndroidManifest.xml and add the following permissions before the <application> tag:

<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.BLUETOOTH" />

iOS

Open ios/Runner/Info.plist and add the keys for Camera and Microphone usage:

<key>NSCameraUsageDescription</key>
<string>This app requires access to the camera for video calling.</string>
<key>NSMicrophoneUsageDescription</key>
<string>This app requires access to the microphone for voice calling.</string>macOS

A Replace with your App ID, Token and channel name from Agora Console

// Replace with your App ID and Token from Agora Console
const String appId = "YOUR_APP_ID";
const String token = "YOUR_TEMP_TOKEN"; 
const String channel = "YOUR_CHANNEL_NAME";

Used to check if the current user has joined the call successfully. The agora object that handles video calling features like joining, leaving, and streaming video.

int? _remoteUid;
bool _localUserJoined = false;
late RtcEngine _engine;

This method sets up Agora by requesting camera and microphone permissions, initializing the video engine, listening for user events, and finally joining a video call channel so the call can start.

Future<void> initAgora() async {
    // Request Permissions
    await [Permission.microphone, Permission.camera].request();
    // Initialize Engine
    _engine = createAgoraRtcEngine();
    await _engine.initialize(const RtcEngineContext(
      appId: appId,
      channelProfile: ChannelProfileType.channelProfileLiveBroadcasting,
    ));
    // Add Event Handlers
    _engine.registerEventHandler(
      RtcEngineEventHandler(
        onJoinChannelSuccess: (RtcConnection connection, int elapsed) {
          setState(() { _localUserJoined = true; });
        },
        onUserJoined: (RtcConnection connection, int remoteUid, int elapsed) {
          setState(() { _remoteUid = remoteUid; });
        },
        onUserOffline: (RtcConnection connection, int remoteUid, UserOfflineReasonType reason) {
          setState(() { _remoteUid = null; });
        },
      ),
    );
    // Enable Video and Join
    await _engine.setClientRole(role: ClientRoleType.clientRoleBroadcaster);
    await _engine.enableVideo();
    await _engine.startPreview();
    await _engine.joinChannel(
      token: token,
      channelId: channel,
      uid: 0,
      options: const ChannelMediaOptions(),
    );
  }
@override
  void initState() {
    super.initState();
    initAgora();
  }

  @override
  void dispose() {
    _engine.leaveChannel();
    _engine.release();
    super.dispose();
  }
Stack(
        children: [
          Center(
            child: _remoteUid != null
                ? AgoraVideoView(
                    controller: VideoViewController.remote(
                      rtcEngine: _engine,
                      canvas: VideoCanvas(uid: _remoteUid),
                      connection: const RtcConnection(channelId: channel),
                    ),
                  )
                : const Text('Waiting for remote user...'),
          ),
          Align(
            alignment: Alignment.topLeft,
            child: SizedBox(
              width: 100,
              height: 150,
              child: _localUserJoined
                  ? AgoraVideoView(
                      controller: VideoViewController(
                        rtcEngine: _engine,
                        canvas: const VideoCanvas(uid: 0),
                      ),
                    )
                  : const CircularProgressIndicator(),
            ),
          ),
        ],
      )

Connect a device and run project.

Congratulations! You should see your local camera feed. If you join the same channel test_channel from another device, you will see the remote video appear.


메타데이터
post_id
b596c1aa5cb3
slug
video-call-app-with-flutter-and-agora-sdk-b596c1aa5cb3
url
https://medium.com/@dheerajprajapat7487/video-call-app-with-flutter-and-agora-sdk-b596c1aa5cb3
canonical_url
https://medium.com/@dheerajprajapat7487/video-call-app-with-flutter-and-agora-sdk-b596c1aa5cb3
author_url
https://medium.com/@dheerajprajapat7487
status
ok
fetched_at
2026-06-22 12:55:45