Open In App

Create a Calling App using React-Native

Building a Calling App using React-Native allows you to create a cross-platform application that supports voice calling. This tutorial will guide you through the process of integrating voice calling functionality into a React-Native app, enabling users to make and receive calls seamlessly.

Preview of final output: Let us have a look at how the final output will look like



Prerequisites:

Approach:

The app will utilize the Agora React Native SDK for voice calling. Key functionalities include initializing Agora Engine, joining and leaving channels, and handling user permissions for microphone and camera.



Steps to create the project:

Step 1: Setup a React Native environment for Voice Calling project

npx react-native init VoicecallApp --template react-native-template-typescript

Step 2: Navigate to the Android folder:

sdk.dir=C:\\PATH\\TO\\ANDROID\\SDK

Step 3: Navigate to the root folder of your project in the terminal and integrate with either:

npm i --save react-native-agora
npx pod-install

Project structure:

The updated dependencies in package.json file will look like:

"dependencies": {
"react": "18.2.0",
"react-native": "0.73.2",
"react-native-agora": "^4.2.6"
},
"devDependencies": {
"@babel/core": "^7.20.0",
"@babel/preset-env": "^7.20.0",
"@babel/runtime": "^7.20.0",
"@react-native/babel-preset": "0.73.19",
"@react-native/eslint-config": "0.73.2",
"@react-native/metro-config": "0.73.3",
"@react-native/typescript-config": "0.73.1",
"@types/react": "^18.2.6",
"@types/react-test-renderer": "^18.0.0",
"babel-jest": "^29.6.3",
"eslint": "^8.19.0",
"jest": "^29.6.3",
"prettier": "2.8.8",
"react-test-renderer": "18.2.0",
"typescript": "5.0.4"
}

Step 4: Add the following code in App.tsx, Replacing the appId, channelName, and token which we will see how ot generate in next step.




//App.tsx
 
import React, { useRef, useState, useEffect } from 'react';
import {
    SafeAreaView,
    ScrollView,
    StyleSheet,
    Text,
    View,
    TouchableOpacity,
} from 'react-native';
import { PermissionsAndroid, Platform } from 'react-native';
import {
    ClientRoleType,
    createAgoraRtcEngine,
    IRtcEngine,
    ChannelProfileType,
} from 'react-native-agora';
 
const appId = 'yourappID';
const channelName = 'dhruvicalling';
const token = 'Yourtoken';
const uid = 0;
 
const App = () => {
    const agoraEngineRef = useRef < IRtcEngine > (); // Agora engine instance
    const [isJoined, setIsJoined] = useState(false);
    const [remoteUid, setRemoteUid] = useState(0);
    const [message, setMessage] = useState('');
 
    useEffect(() => {
        // Initialize Agora engine when the app starts
        setupVoiceSDKEngine();
    }, []);
 
    const join = async () => {
        if (isJoined) {
            return;
        }
        try {
            agoraEngineRef.current?.setChannelProfile(
                ChannelProfileType.ChannelProfileCommunication,
            );
            agoraEngineRef.current?.joinChannel(token, channelName, uid, {
                clientRoleType: ClientRoleType.ClientRoleBroadcaster,
            });
        } catch (e) {
            console.log(e);
        }
    };
 
    const setupVoiceSDKEngine = async () => {
        try {
            if (Platform.OS === 'android') {
                await getPermission();
            }
            agoraEngineRef.current = createAgoraRtcEngine();
            const agoraEngine = agoraEngineRef.current;
            agoraEngine.registerEventHandler({
                onJoinChannelSuccess: () => {
                    showMessage('Successfully joined the channel'+ channelName);
                    setIsJoined(true);
                },
                onUserJoined: (_connection, Uid) => {
                    showMessage('Remote user joined with uid ' + Uid);
                    setRemoteUid(Uid);
                },
                onUserOffline: (_connection, Uid) => {
                    showMessage('Remote user left the channel. uid: ' + Uid);
                    setRemoteUid(0);
                },
            });
            agoraEngine.initialize({
                appId: appId,
            });
        } catch (e) {
            console.log(e);
        }
    };
 
    const leave = () => {
        try {
            agoraEngineRef.current?.leaveChannel();
            setRemoteUid(0);
            setIsJoined(false);
            showMessage('You left the channel');
        } catch (e) {
            console.log(e);
        }
    };
 
    function showMessage(msg: string) {
        setMessage(msg);
    }
 
    return (
        <SafeAreaView style={styles.container}>
            <Text style={styles.header}>Calling App</Text>
            <View style={styles.buttonContainer}>
                <TouchableOpacity onPress={join} style={styles.joinButton}>
                    <Text style={styles.buttonText}>Join</Text>
                </TouchableOpacity>
                <TouchableOpacity onPress={leave} style={styles.leaveButton}>
                    <Text style={styles.buttonText}>Leave</Text>
                </TouchableOpacity>
            </View>
            <ScrollView style={styles.scroll}
                        contentContainerStyle={styles.scrollContainer}>
                {isJoined ? (
                    <Text style={styles.infoText}>Local user uid: {uid}</Text>
                ) : (
                    <Text style={styles.infoText}>Join a channel</Text>
                )}
                {isJoined && remoteUid !== 0 ? (
                    <Text style={styles.infoText}>
                        Remote user uid: {remoteUid}
                    </Text>
                ) : (
                    <Text style={styles.infoText}>
                        Waiting for a remote user to join
                    </Text>
                )}
                <Text style={styles.messageText}>{message}</Text>
            </ScrollView>
        </SafeAreaView>
    );
};
 
const styles = StyleSheet.create({
    container: {
        flex: 1,
        alignItems: 'center',
        backgroundColor: '#f0f0f0',
    },
    header: {
        fontSize: 24,
        fontWeight: 'bold',
        marginVertical: 20,
    },
    buttonContainer: {
        flexDirection: 'row',
        justifyContent: 'center',
        marginBottom: 20,
    },
    joinButton: {
        paddingHorizontal: 25,
        paddingVertical: 10,
        borderRadius: 8,
        backgroundColor: '#4CAF50',
        margin: 5,
    },
    leaveButton: {
        paddingHorizontal: 25,
        paddingVertical: 10,
        borderRadius: 8,
        backgroundColor: '#E57373',
        margin: 5,
    },
    buttonText: {
        color: '#ffffff',
        fontWeight: 'bold',
        fontSize: 16,
    },
    scroll: {
        flex: 1,
        backgroundColor: '#ffffff',
        width: '90%',
        padding: 10,
        borderRadius: 8,
    },
    scrollContainer: {
        alignItems: 'center',
    },
    infoText: {
        fontSize: 18,
        marginVertical: 10,
    },
    messageText: {
        fontSize: 16,
        fontStyle: 'italic',
        color: '#555555',
    },
});
 
const getPermission = async () => {
    if (Platform.OS === 'android') {
        await PermissionsAndroid.requestMultiple([
            PermissionsAndroid.PERMISSIONS.RECORD_AUDIO,
        ]);
    }
};
 
export default App;

NOTE: MAKE SURE TO REPLACE THE APPID AND TOKEN WITH YOUR GENERATED ONES.

Step 5: Generating appId and token in Agora as we are using Agora SDK for call connection.

Steps to run the application:

npx react-native start

Output:


Article Tags :