Talk to us
Talk to us
menu

How to Develop a Voice Call App with Flutter

How to Develop a Voice Call App  with Flutter

Integrating voice call functionality into your app using Flutter is a powerful way to elevate real-time communication—whether for social platforms, remote collaboration, or personalized customer support. By leveraging the right tools and frameworks, you can seamlessly implement high-quality audio interactions, real-time connectivity, and secure data transmission. This blog will walk you through the demo experience guide, the essential steps to build a voice call app with Flutter, highlighting how ZEGOCLOUD SDK accelerates development, simplifies complex features, and deliver a polished user experience. Let’s dive into creating a solution that keeps users connected, engaged, and impressed.

Try the Demo Now

Try ZEGOCLOUD’s demo to explore the audio calling feature enabled by the Voice Call SDK.

Before you get started

Before you run the demo, you need to prepare the environment and get required information from the ZEGOCLOUD console.

Get the demo

Download the zipped package of the demo and unzip it to get the demo folder.

Prepare the environment

Please ensure your development environment fulfills the following requirements:

  • Windows: version 7 or later
  • macOS: version 11.0 or later
  • Web browser: Chrome 58 or later, Firefox 56 or later, Safari 11 or later, Opera 45 or later.
  • Flutter: version 2.0 or later.
  • iOS: version 12 .0 or later. The iOS device or simulator must support audio and video communication, and you are advised to use a real device.
  • Android: version 4.4 or later. The Android device or simulator must support audio and video communication, and you are advised to use a real device with the debugging option enabled.
  • Connection established between the device and Internet

Make sure your development environment meet the following requirements:

  • Android Studio: Select Preferences > Plugins, search for the Flutter plug-in, and download it. Then configure the path to the Flutter SDK that has been prepared in the plug-in.
  • VS Code: In the app store, search for the Flutter extension and download it.

After configuring the Flutter environment in any of the preceding development environments, run flutter doctor in the CLI (terminal). If any dependencies are not prepared, download them as prompted.

Get the required information

Navigate to the ZEGOCLOUD Admin Console to set up a new project, and obtain the AppID and AppSign for your project.

Launch the demo

The demo provided here can be run on iOS, Android, and web platforms; however, the method of running it varies depending on the target platform.

Run on an iOS/Android device

The sample codes does not include the appID and appSign parameters, which are necessary for SDK initialization. Therefore, to make the sample codes ready to run, you should set the AppID and AppSign obtained in advance in the lib/utils/zego_config.dart file from the unzipped folder.

According to your IDE, please follow the right instruction:

Android Studio
  1. Open Android Studio and select Open an existing Android Studio project to open the zego-express-flutter-sdk folder.
  2. Use a USB cable to connect your Android or iOS device to your computer.
  3. Click Run in the upper right corner of Android Studio to run the sample code.
Visual Studio Code
  1. Launch VS Code and go to File > Open to open the zego-express-flutter-sdk folder.
  2. In the file manager on the left of VS Code, navigate to and double-click example/main.dart to open the main entry file.
  3. Connect your Android or iOS device to your computer.
  4. From the top menu, select Run > Run Without Debugging to launch the sample app.

Run on a web browser

  • Open the zego-express-flutter-sdk folder on VS code and navigate to the the lib/utils/zego_config.dart file to set the appIDuserIDuserName, and token parameters. For your convenience, you can go to the ZEGOCLOUD Console to get a temporary token. For reference, please read the “Project Information” in How to view project information.
  • In VS Code’s left-hand file manager, right-click on example and choose Open in Terminal from the menu.
  • In the terminal, execute flutter run -d chrome --web-renderer html to launch the sample code.

Steps-by-steps Guide to Make an Call with ZEGOCLOUD

Building a web voice call app is exciting but has some technical challenges. To create one, you’ll need skills in both front-end and back-end development. In this guide, we’ll show you how to build a voice call app using the ZEGOCLOUD Voice Call SDK. We’ll take you step by step—from setting up your tools to adding voice call features to your web app. Whether you’re working on the user interface or the server setup, this guide makes it simple to add live voice calls to your project.

Before you get started

Step 1. Create a ZEGOCLOUD project

Go to ZEGOCLOUD Admin Console to create a project so as to get the AppID and AppSign.

Step 2. Prepare the environment

  • Flutter SDK: ≥ v2.0
    Mobile OS
  • iOS: 12.0+ (physical device or simulator with A/V support)
  • Android: 4.4+ (physical device/emulator; enable USB debugging for physical devices)
    Desktop OS
  • Windows: 8+
  • macOS: 10.14+
    Web Compatibility
  • Browsers: Chrome (≥58), Firefox (≥56), Safari (≥11), Opera (≥45)
    Linux Distributions
  • Debian 10+
  • Ubuntu LTS: 20.04, 22.04, 24.04

(Note: Physical devices are strongly recommended over emulators for audio testing.)

Import the SDK

Run the following code in your project root directory:

flutter pub add zego_express_engine

Integrate the SDK into your development project.

import 'package:zego_express_engine/zego_express_engine.dart';

Configure Permissions

Based on your application’s requirements, define and enable the necessary permissions.

Configure your Android app

Navigate to the app/src/main directory, open the AndroidManifest.xml file, and add the folllowing required permissions.

<!-- Permissions required by the SDK -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />

<!-- Permissions required by the Demo App -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />

<uses-feature android:glEsVersion="0x00020000" android:required="true" />

Starting with Android 6.0 (Marshmallow), critical permissions require dynamic runtime requests and cannot be granted solely through static declarations in AndroidManifest.xml. To implement any of the following functions:

  • For Flutter Projects:
    • Search for third-party Flutter plugins on pub.dev to manage runtime permissions.
    • Follow the plugin’s documentation to request permissions at runtime.
  • For Native Android Integration:
    • Use the following code in your Android native layer. Note that requestPermissions is a method of the Activity class:
String[] permissionNeeded = {
    "android.permission.RECORD_AUDIO"};

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    if (ContextCompat.checkSelfPermission(this, "android.permission.RECORD_AUDIO") != PackageManager.PERMISSION_GRANTED) {
        requestPermissions(permissionNeeded, 101);
    }
}

Configure your iOS app

Open the project and access “TARGETS > Info > Custom iOS Target Properties”.

Custom iOS Target Properties - Flutter voice call

Click the “+” button, and add microphone permissions.

  • Privacy - Microphone Usage Description

Prevent code obfuscation for Android devices

To prevent obfuscation of the SDK public class names, do the following:

  • In your project’s your_project > android > app folder, create a proguard-rules.pro file with the following content as shown below:
-keep class **.zego.** { *; }
  • Add the following config code to the release part of the your_project/android/app/build.gradle file.
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
Prevent code obfuscation for Android devices

Configure your Web app

For comprehensive guidance on Flutter Web development best practices and common challenges, consult the official Flutter Web FAQ.

To log in a room on your Web app before starting a voice call , you must use Token. You can read the doc Use Tokens for authentication to know how to generate tokens.

Configure your macOS and Windows apps

For macOS and Windows applications, the ZEGOCLOUD Voice Call SDK requires no additional platform-specific configurations. However, you must follow the docs below to initialize your Flutter project’s core settings:

Create the ZegoExpressEngine instance

Invoke the createEngineWithProfile interface and provide your registered AppID and AppSign. Note that the appSign parameter is not supported on the Web platform. For security reasons, ensure appSign is never exposed in web-based implementations.

ZegoEngineProfile profile = ZegoEngineProfile(
    appID, // Register with the official website and obtain the data in the format similar to 1234567890.
    ZegoScenario.General, // General scenario integration
    appSign: appSign,// Register with the official website and obtain a string of 64 characters in the format similar to'0123456789012345678901234567890123456789012345678901234567890123'(64 characters in total), the Web platform does not need to be passed in
    enablePlatformView: true); //Needs to be true on Web platform
// Create an engin
ZegoExpressEngine.createEngineWithProfile(profile);

Listen for critical events

You should listen for critical room events including room state updates, room user updates, room stream updates.

  • onRoomStreamUpdate: Monitors updates to active streams in the room. When new streams are published or existing streams are removed, the SDK triggers this callback. Use the startPlayingStream method to play new streams or stopPlayingStream to halt playback of removed streams within this callback.
  • onRoomStateUpdate: Tracks changes to the current room connection state. The SDK fires this callback for events like disconnections or login authentication failures. Implement logic here to handle connection state transitions (e.g., retries, error alerts).
  • onRoomUserUpdate: Detects changes to user presence in the room. The SDK triggers this callback when users join or leave the room. Use it to update participant lists or manage user-specific interactions.

//The following are commonly used room-related callbacks

//Stream status update
ZegoExpressEngine.onRoomStreamUpdate = (String roomID, ZegoUpdateType updateType, List<ZegoStream> streamList) {
     // Implement event callbacks as needed
};

// Room status update callback
ZegoExpressEngine.onRoomStateUpdate = (String roomID, ZegoRoomState state, int errorCode, Map<String, dynamic> extendedData) {
     // Implement event callbacks as needed
};

//User status update
ZegoExpressEngine.onRoomUserUpdate = (String roomID, ZegoUpdateType updateType, List<ZegoUser> userList) {
     // Implement event callbacks as needed
};

Disable the camera

To achieve a voice call scenario, after creating the engine, call enableCamera to turn off the camera. By that, the SDK does not activate the engine’s video module. Once the camera is turned off, it will no longer require requesting camera permissions, and will not publish video streams.

ZegoExpressEngine.instance.enableCamera(false);

Log in to a room

Initialize a ZegoUser by passing the userID parameter, then utilize the loginRoom interface with the roomID and user parameters to enter the room. When invoked, this interface will create and log into the room automatically if it is not present.

// Create a user object
ZegoUser user = ZegoUser.id('user1');

// Only ZegoRoomConfig with "isUserStatusNotify" set to true will receive the onRoomUserUpdate callback
ZegoRoomConfig config = ZegoRoomConfig.defaultConfig();
config.isUserStatusNotify = true;

// If using AppSign authentication, leave the token parameter empty.
// For enhanced security with Token authentication (required for web platforms), see:
// [Use Tokens for authentication](https://www.zegocloud.com/docs/video-call/token?platform=flutter&language=dart)
// config.token = "xxxx";

// Start logging into the room
ZegoExpressEngine.instance.loginRoom('room1', user, config: config);

Publish a stream

Call the startPublishingStream interface, provide the stream ID parameter “streamID”, to transmit the local audio stream to remote users.

ZegoExpressEngine.instance.startPublishingStream("streamID");

Listen to the onPublisherStateUpdate callback to track real-time streaming state changes. This callback triggers when the streaming interface is successfully initialized but later encounters status changes, such as streaming exceptions caused by network interruptions. During automatic streaming retry attempts, the SDK uses this callback to push synchronized status change notifications to your application.

ZegoExpressEngine.onPublisherStateUpdate = (String streamID, ZegoPublisherState state, int errorCode, Map<String, dynamic> extendedData) {
    // Your business logic
};

Play a stream

Call the startPlayingStream interface, provide the stream ID parameter “streamID”, to receive the remote audio stream.

ZegoExpressEngine.instance.startPlayingStream(streamID);

Listen to the onPlayerStateUpdate callback to track real-time stream playback state changes. This callback triggers when the playback interface is successfully initialized but later encounters status changes, such as playback exceptions caused by network interruptions. During automatic playback retry attempts, the SDK uses this callback to push synchronized status change notifications to your application.

ZegoExpressEngine.onPlayerStateUpdate = (String streamID, ZegoPlayerState state, int errorCode, Map<String, dynamic> extendedData) {
    // Your business logic
};

Experience the real-time voice call

For the best experience, test on an actual phone. Then, go to the ZEGO Express Web Demo and enter the same AppID, Server, and RoomID to join the same room. If everything works, you’ll hear both ends.

Terminate Stream Publishing & Playback

Call the stopPublishingStream interface to terminate the transmission of local audio streams to remote users.

ZegoExpressEngine.instance.stopPublishingStream();

Use the stopPlayingStream interface to terminate playback of the remote audio stream.

ZegoExpressEngine.instance.stopPlayingStream(streamID);

Log out

Use the logoutRoom interface to exit the room.

ZegoExpressEngine.instance.logoutRoom('room1');

Release the resource

When you no longer need the voice call capability, you can call the destroyEngine method to destroy the engine and release the resources.

ZegoExpressEngine.destroyEngine();

Conclusion

When building a voice call application with Flutter, the ZEGOCLOUD SDK streamlines development while elevating functionality. It empowers developers to integrate seamless real-time communication, robust voice capabilities, and reliable data security efficiently. For Flutter-driven projects, it stands as an essential tool for creating dynamic, engagement-focused calling solutions. Register now to transform your chat app into something extraordinary and unlock boundless potential for user connection!

Let’s Build APP Together

Start building with real-time video, voice & chat SDK for apps today!

Talk to us

Take your apps to the next level with our voice, video and chat APIs

Free Trial
  • 10,000 minutes for free
  • 4,000+ corporate clients
  • 3 Billion daily call minutes

Stay updated with us by signing up for our newsletter!

Don't miss out on important news and updates from ZEGOCLOUD!

* You may unsubscribe at any time using the unsubscribe link in the digest email. See our privacy policy for more information.