Flutter Video Calling App
Tags: flutter, mobile
Published: 2023-04-16 11:34:58

In this article, You will be learning how to build a Video calling using the [Video Call](https://www.zegocloud.com/product/video-call) SDK and API provided by the [ZEGOCLOUD](http://bit.ly/3LVErPZ). Let me introduce ZEGOCLOUD it is a global communication service provider which provides developer-friendly and powerful SDK & APIs to build many communication feature on mobile app and web app, such as video call, chat, video conference, live streaming,etc.

When you register an account with ZEGOCLOUD you will receive a FREE 10,000 minutes to build and test your app and the cool part is it does not require any credit card to register a new account.

### Create an Account
Use the link to register a new account http://bit.ly/3FFkj0q

### Create Project
Once you have successfully registered an account, next step will be to create a project. Click on the Overview menu and click on **create your first project** button.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/47u6b17y4d6kiiselsgi.png)

#### Select a use case for your app

Next step you will need to select a use case for your app, since we are [building a Video Call app](https://www.zegocloud.com/blog/flutter-callkit) select **Voice & Video Call** for the list of options and click on **Next** button

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m6qpcoz2us2b6ou5flge.png)

#### Select the most appropriate way to get started

Next step you will need to provide a **Project Name**. I will provide a project name as **ChattyApp**. Here you will have an option to choose UIKit or SDK, we will be using a UIKit to build an app as it provides a pre-build UI to speed up our development. Click on the **Start with UIKits button**

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ec216ypqx64p2d0jmre1.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iira6g00ajiknqo9s6nq.png)

### Framework Selection
Next step you will need to select a **Framework**. We will be creating a Flutter app , so let's select Flutter as our framework.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/si96txre2fn83igzfueg.png)

### UI Configuration
Next step you will need to select a **1-on 1 Call** option since we will be build a 1-1 Video Calling App and click on **Save & Start to integrate button**

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pqrb74be2nzcl5rp9pyy.png)

### Obtain Configuration
Next step you will need to obtain the **AppID** and **AppSign** configuration key.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0smdnowiqvo2v7xczvns.png)

## Create the Flutter application
Now you will need to create the Flutter application, run the below command in your terminal.

```
flutter create chatty --org io.mobileacademy.io
```

## Add Dependencies
Next let us add our dependencies. Open your _pubspec.yaml_ file and add **zego_uikit_prebuilt_call: ^3.2.0**
 in the dependencies section.

```
dependencies:
  flutter:
    sdk: flutter


  cupertino_icons: ^1.0.2
  # https://pub.dev/packages/zego_uikit_prebuilt_call/install
  zego_uikit_prebuilt_call: ^3.2.0
```

## Create UI
Next inside the _lib_ folder create a new folder _screen_ and inside the _screen_ folder create a new file **video_call_screen.dart** and paste the below code.

```
import 'package:chatty/const.dart';
import 'package:flutter/material.dart';
import 'package:zego_uikit_prebuilt_call/zego_uikit_prebuilt_call.dart';


class VideoCallScreen extends StatefulWidget {
  final String userId;
  final String userName;
  final String callId;
  const VideoCallScreen({
    Key? key,
    required this.userId,
    required this.userName,
    required this.callId,
  }) : super(key: key);

  @override
  State<VideoCallScreen> createState() => _VideoCallScreenState();
}

class _VideoCallScreenState extends State<VideoCallScreen> {
  @override
  Widget build(BuildContext context) {
    return ZegoUIKitPrebuiltCall(
      appID: appId, // Fill in the appID that you get from ZEGOCLOUD Admin Console.
      appSign: appSign, // Fill in the appSign that you get from ZEGOCLOUD Admin Console.
      userID: widget.userId,
      userName: widget.userName,
      callID: widget.callId,
      // You can also use groupVideo/groupVoice/oneOnOneVoice to make more types of calls.
      config: ZegoUIKitPrebuiltCallConfig.oneOnOneVideoCall() 
    );
  }
  
}
```

You can see from the above code that _ZegoUIKitPrebuiltCall_ constructor requires few argument's.
**appID**: You can get the appID from ZEGOCLOUD Admin Console
**appSign**: You can get the appSign from ZEGOCLOUD Admin Console
**userID**: You can provide a unique user ID for each user
**userName**: You can provide a user name, which will be displayed in the call screen.
**callID**: This is a unique ID that is required to make and connect a call, both party should have a same call ID.

Next let us replace our **main.dart** file code with the below code.
```
import 'dart:math';

import 'package:chatty/screen/video_call_screen.dart';
import 'package:flutter/material.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(      
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final GlobalKey<FormState>  _formKey = GlobalKey();
  final TextEditingController _nameController = TextEditingController();
  final TextEditingController _callIdController = TextEditingController();
  
  @override
  void dispose() {
    _nameController.dispose();
    _callIdController.dispose();
    super.dispose();
  }

  void _generateCallId(){
    final value = Random().nextInt(1000) + 1;
    setState(() {
      _callIdController.text = value.toString();
    });
  }

  @override
  Widget build(BuildContext context) {    
    return Scaffold(
      appBar: AppBar(        
        title: Text(widget.title),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Center(        
          child: SingleChildScrollView(
            child: Column(          
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Form(
                  key: _formKey,
                  child: Column(
                    children: [
                      TextFormField(
                        controller: _nameController,
                        decoration: InputDecoration(
                          labelText: 'Name',
                          hintText: 'enter your name',
                          border: OutlineInputBorder(
                            borderRadius: BorderRadius.circular(8.0)
                          )
                        ),
                        validator: (value) {
                          if (value == null || value == '') {
                            return 'Please enter your name';
                          }
                          return null;
                        },
                      ),
                
                      const SizedBox(height: 16.0,),
                
                      TextFormField(
                        controller: _callIdController,
                        decoration: InputDecoration(
                          labelText: 'Call Id',
                          hintText: 'enter your call Id',
                          border: OutlineInputBorder(
                            borderRadius: BorderRadius.circular(8.0)
                          )
                        ),
                        validator: (value) {
                          if (value == null || value == '') {
                            return 'Please enter call id';
                          }
                          return null;
                        },
                      )
                    ],
                  ),
                ),
                
                FilledButton.tonal(
                  onPressed: () {
                    _generateCallId();
                  }, 
                  child: const Text('Generate CallId'),
                ),
                
                FilledButton.tonal(
                  onPressed: () {
                    _startVideoCall();
                  }, 
                  child: const Text('Video Call'),
                )
              ],
            ),
          ),
        ),
      ),
      
    );
  }

  void _startVideoCall() {
    final isValid = _formKey.currentState?.validate();
    if (isValid != null && isValid) {
      Navigator.of(context).push(
        MaterialPageRoute(builder: (_) => VideoCallScreen(
          userId: (Random().nextInt(100) + 1).toString(), 
          userName: _nameController.text, 
          callId: _callIdController.text),
        )
      );
    }
  }
}

```
In the above code we have a two main function **_generateCallId** this function is used to generate a random number for call ID and the next one is **_startVideoCall** this function is used to validate a form and if the form is valid will open our VideoCallScreen

## iOS Setup
Next you will need to setup the camera and microphone permission for iOS. Open your **Info.plist** from _your_project/ios/Runner/_ add the following code inside the "dict" tag:
```
	<key>NSCameraUsageDescription</key>
	<string>We require camera access to connect to a call</string>
	<key>NSMicrophoneUsageDescription</key>
	<string>We require microphone access to connect to a call</string>
```


Next to use the notifications and build your app correctly, open ios folder in Xcode and navigate to the Build Settings tab, and set the following build options for your target app.

Refer to and set the following build options:

In the Runner Target:   

    a. Build Libraries for Distribution -> NO

    b. Only safe API extensions -> NO

    c. iOS Deployment Target -> 11 or greater

In other Targets:

    a. Build Libraries for Distribution -> NO

    b. Only safe API extensions -> YES

## Android Setup
Next you will need to open the your_project/android/app/build.gradle file, and modify the compileSdkVersion to 33 and minSdkVersion to 21 or higher

#### Android Permission

Open the file your_project/app/src/main/AndroidManifest.xml, and add the following code:
```
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.RECORD_AUDIO" />
   
```

## Build and Run App
Finally it's time to run your app. To test the video call, you will need to run in the real device.

Conclusion
As you can see, adding the video call option to your flutter app is very easy and simple using the [pre-built UIKits](https://www.zegocloud.com/uikits) from ZEGOCLOUD, please visit their website to get more information about their products and services.

I hope this tutorial has been useful to you, see you in the next article.