1. Vonage Learn
  2. Blog
  3. 2021
  4. 04
  5. 22
  6. How to Make Phone Calls Using Android and React Native
How to Make Phone Calls Using Android and React Native

< Tutorial />

How to Make Phone Calls Using Android and React Native

This blog post will take you through a project, which will show you how to use the Vonage Client SDK to build a React Native Android app which will call a phone number. If you would like to explore using the Client SDK with iOS, check out this blog post.

Prerequisites

Set Up React Native

To build and run a React Native app, you first need to install the dependencies, Node and Watchman. You can do so using Homebrew. In your terminal run:

brew install node
brew install watchman

If you already have Node installed, ensure it is Node 12 or newer. You can find more information about getting your environment set up in the React Native documentation.

Clone the Project

You can clone the project to your local machine by running the following command in your terminal:

git clone git@github.com:nexmo-community/react-native-app-to-phone.git

Then change directory into the new folder cd react-native-app-to-phone.

Now that you have cloned the project, you can install the project dependencies. You can install the React Native specific dependencies by running npm install. This command will install the dependencies listed in the package.json file. A dependency you should note is react-native-permissions, an open-source project that provides a unified way to request permissions on both iOS and Android.

React Native also needs some environment variables to be set up. Edit your PATH with:

export ANDROID_HOME=$HOME/Library/Android/sdk
export PATH=$PATH:$ANDROID_HOME/emulator
export PATH=$PATH:$ANDROID_HOME/tools
export PATH=$PATH:$ANDROID_HOME/tools/bin
export PATH=$PATH:$ANDROID_HOME/platform-tools

Once done, load the config into the current shell using the source command. You can find more detailed instructions in the React Native documentation.

The Vonage Application

To create the application, we will be using our command-line interface. If you have not set up the CLI yet, do so by running the command nexmo setup API_KEY API_SECRET in your terminal, where the API Key and Secret are the API key and secret found on your account’s settings page.

Create an NCCO

A Call Control Object (NCCO) is a JSON array that you use to control the flow of a Voice API call. The NCCO must be public and accessible by the internet. To accomplish that, you will be using a GitHub Gist that provides a convenient way to host the configuration.

Go to https://gist.github.com and enter call.json into the "Filename including extension" box. The contents of the gist will be the following JSON:

[
    {
        "action": "talk",
        "text": "Please wait while we connect you."
    },
    {
        "action": "connect",
        "endpoint": [
            {
                "type": "phone",
                "user": "447000000000"
            }
        ]
    }
]

Create the gist, then click the "Raw" button to get a URL for your NCCO. Keep note of it for the next step.

ncco raw button

Create a Vonage Application

You now need to create a Vonage Application. An application contains the security and configuration information you need to connect to Vonage. In your terminal, create a Vonage application using the following command replacing GIST_URL with the URL from the previous step:

nexmo app:create "Phone To App Tutorial" --capabilities=voice --keyfile=private.key  --voice-event-url=https://example.com/ --voice-answer-url=GIST_URL 

A file named .nexmo-app is created in your project directory and contains the newly created Vonage Application ID and the private key. A private key file named private.key is also created.

Create a JWT

The Client SDK uses JWTs for authentication. The JWT identifies the user name, the associated application ID and the permissions granted to the user. It is signed using your private key to prove that it is a valid token. Create a user for your application, you can do so by running nexmo user:create name="Alice" to create a user called Alice. Then create a JWT for the Alice user by running the following command replacing APP_ID with your application ID from earlier:

nexmo jwt:generate ./private.key exp=$(($(date +%s)+21600)) acl='{"paths":{"/*/users/**":{},"/*/conversations/**":{},"/*/sessions/**":{},"/*/devices/**":{},"/*/image/**":{},"/*/media/**":{},"/*/applications/**":{},"/*/push/**":{},"/*/knocking/**":{}}}' sub=Alice application_id=APP_ID

Run the Project

First, you will need to prepare an Android device for the project to run on. Open the project's android directory in Android Studio. The project will start loading and download the dependencies, including the Client SDK, via the Gradle Sync. You can view the dependencies on the Android app's build.gradle file (android/app/build.gradle). In the toolbar at the top, look for the AVD Manager button:

avd manager button

If you already have an emulator setup, run it. If not, click the Create Virtual Device button and go through the wizard. Make sure to create a device with API level 29 or newer as required by React Native.

emulator

With all the dependencies installed and the emulator running, you can now run the project. Start Metro with npx react-native start. With that running, open a new terminal window in the same directory and run npx react-native run-android. This command will build and run the android project for the emulator you prepared. The app consists of a label showing the connection status, a label to show the call status and an action button.

android app UI

If you open the App.tsx folder you can take a look at how this is built in the render function:

render() {
    return (
      <SafeAreaView>
        <View style={styles.status}>
          <Text>
            {this.state.status}
          </Text>

          <View style={styles.container}>
            <Text style={styles.callState}>
              Call Status: {this.state.callState}
            </Text>
            <Pressable
              style={styles.button}
              onPress={this.state.callAction}>
              <Text style={styles.buttonText}>{this.state.button}</Text>
            </Pressable>
          </View>
        </View>
      </SafeAreaView>
    );
}

If you are have used React before, this syntax will be familiar to you. A Text component is used for the labels, a Pressable component for the button, along with the styling CSS at the top. All three components make use of state. State data is parameters for components that will change over time. The state is initialized at the top of the App class in the constructor with default information. You can paste the JWT you created in the previous step and save the file (CMD + S). The simulator will reload, and now when you press the login button, the Client SDK will connect. You now will be able to place a phone call.

android app UI logged in

How to Communicate With Native Code

Permissions

As mentioned earlier, the project uses the react-native-permissions library to make working with permissions across platforms easier. In the componentDidMount function, you can see the extent of the code required in JavaScript to request permissions, along with adding the permission to the AndroidManifest.xml file. :

if (Platform.OS === 'ios') {
    request(PERMISSIONS.IOS.MICROPHONE);
} else if (Platform.OS === 'android') {
    request(PERMISSIONS.ANDROID.RECORD_AUDIO);
}

The Client SDK

The Client SDK is a native dependency, so there needs to be a way to communicate between the JavaScript code on App.tsx and the native Android code. There are two ways of doing this depending on the direction of the information. NativeModules expose native classes to JavaScript to allow for you to execute native code. The NativeEventEmitter API allows native code to send signals to JavaScript code. Look at the componentDidMount function in the App class. You can see that the JavaScript code is listening for two different signals, onStatusChange and onCallStateChange, which will update the UI and action that the button performs.

eventEmitter.addListener('onStatusChange', (data) => {
...
});

eventEmitter.addListener('onCallStateChange', (data) => {
...
});

diagram showing the flow between javascript code and native code

If you open the android directory of the project you will see a class called EventEmitter (android/app/src/main/java/com/rnapptophone/EventEmitter.java). The EventEmitter class has a function that sends the signals to the JavaScript code.

public void sendEvent(String eventName, @Nullable WritableMap params) {
    this.context.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(eventName, params);
}

These functions are called from the ClientManager class (iandroid/app/src/main/java/com/rnapptophone/ClientManager.java). The ClientManager class is a wrapper around the Client SDK. Both classes extend the ReactContextBaseJavaModule class, which requires both subclasses to return a name as a String which is used as the NativeModules name. ClientManager.java makes use of an annotation, ReactMethod. This annotation marks the method to be exposed to JavaScript. For example, here is the login function that you would have used earlier:

@ReactMethod
public void login(String jwt) {
    client.login(jwt);
}

This is how it would be called in JavaScript:

ClientManager.login("ALICE_JWT")

What Next?

You can find the complete project on GitHub, and the iOS version of this blog on learn.vonage.com. You can do a lot more with the Client SDK, learn more on developer.vonage.com.

Comments currently disabled.