An app showcasing the integration of react-native-callkeep library with 100ms React Native SDK to enable VOIP calls such as Whatsapp calls. When a data notification is received, the app presents users a screen with "Answer" and "Reject" buttons with react-native-callkeep library. Upon answering, users are taken to an active call screen UI within the app.
The app has implemented basic video call conferencing using v1.6.2
of the 100mslive/react-native-hms
library. It uses
Room Code for generating 100ms Auth Token.
Branch Setup:
-
origin/main
branch has a basic video call conferencing feature with 100ms -
origin/android-feature-fcm-support
branch has implemented support for Firebase cloud messaging. This allows us to send data notifications to the app even when it's in an inactive state. -
origin/android-feature-callkeep-support
branch has implemented support for Reacty Native Callkeep library.
Important Note: React Native Callkeep library and Firebase support are added only for Android. Therefore, the iOS build can only be made on the
main
branch.
rn-callkit-demo-1-25x.mp4
We will implement a basic feature in which the App can receive an incoming call and can answer it. When the user answers the incoming call, it should be able to successfully do conferencing calls with the caller.
You can follow 100ms React Native quickstart guide to quickly implement 100ms React Native SDK within your app.
The main
branch of this repository implements the basic video call conferencing feature with 100ms React Native SDK.
You can also checkout quickstart app or advanced example app which implements all the features provided by 100ms.
By adding support for Firebase Cloud Messaging, We can send data notifications to the application to notify it about the incoming call, so that it can show Incoming Call UI screen.
Follow the React Native Firebase guide for this.
This library allows us to show the Incoming call UI screen on receive of a data notification from FCM and provides many other features. Follow the React Native Callkeep library official guide to implement it in your app.
Also, check out React Native Callkeep library changes diff
After completing the above steps, Rebuild your application and check it is working correctly. Then follow the below steps to quickly integrate Callkeep library with 100ms RN SDK.
RNCallkeep library requires some permissions before its features can be used without any problem.
We need to call the RNCallKeep.setup
method on the main screen of the app so that it always gets called whenever the app starts.
In this way, We will already have the required permissions before the app shows the call screen from an inactive state.
We are calling the RNCallKeep.setup
method in FCMSetup
component
which is always rendered irrespective of the screen user is on.
Now let's say, App is in the inactive state, and we already have the required Callkeep permissions because we
called the RNCallKeep.setup
method when the app ran for the first time.
When the app is in the inactive state, You can send a data-only notification with "high" priority to the app using FCM.
We will also send "Room Code" as a payload so that we can generate Auth Token in the app and add a user in the room -
{
"message": {
"token": "<Paste FCM Token Here>",
"android": { "priority": "HIGH" },
"data": { room_code: "nih-bkn-vek" }
}
}
For the app's inactive state, the App will receive the data notification in the callback function passed to the messaging().setBackgroundMessageHandler
method -
messaging().setBackgroundMessageHandler(async remoteMessage => {
console.log('FCM Message handled in the background!', JSON.stringify(remoteMessage, null, 2));
if (remoteMessage.data.room_code) {
// If Room Code is available in payload data
// We can show the incoming screen UI to the user.
}
});
In the callback function, which is called on receiving of notification, We need to again call the RNCallKeep.setup
method before showing the Incoming Call UI.
After calling the RNCallKeep.setup
method, We can show the Incoming Call UI by calling the RNCallKeep.displayIncomingCall
method and passing the received "Room Code" as the first argument.
The Incoming call screen should be presented to the user at this point.
Now, when the user presses the "Call Answer" button, We need to dismiss the Incoming Call UI and navigate the user to our app with the "Room Code" payload.
We need this "Room Code" payload to generate Auth Token and add users to the room. When "Room Code" data is detected at the start of the app, we can directly navigate the user to the "Meeting screen" instead of the Welcome screen.
Then, Inside the Meeting screen, we can set up the HMSSDK instance, generate Auth token and call the join
function to add the user to the room.
messaging().setBackgroundMessageHandler(async remoteMessage => {
console.log('FCM Message handled in the background!', JSON.stringify(remoteMessage, null, 2));
// If Room Code is available in payload data
// We can show the incoming screen UI to the user.
if (remoteMessage.data.room_code) {
// Step 1: Setup RNCallKeep Native Module
RNCallKeep.setup({
android: {
alertTitle: 'Permissions required',
alertDescription: 'This application needs to access your phone accounts',
cancelButton: 'Cancel',
okButton: 'ok',
imageName: 'phone_account_icon',
// additionalPermissions: [PermissionsAndroid.PERMISSIONS.example],
additionalPermissions: [],
// Required to get audio in the background when using Android 11
foregroundService: {
channelId: 'com.company.my',
channelName: 'Foreground service for my app',
notificationTitle: 'My app is running in the background',
// notificationIcon: 'Path to the resource icon of the notification',
},
}
});
// Step 2: Set user availability
RNCallKeep.setAvailable(true);
// Step 3: Show the Incoming Call UI screen to the user with Room Code as callUUID
RNCallKeep.displayIncomingCall(
remoteMessage.data.room_code,
'100msPhoneNumber',
'100ms Call',
'number',
false,
);
// Step 4: Add a listener for when the user clicks on the answer button
RNCallKeep.addEventListener('answerCall', (data) => {
// Remove this listener when it is called
RNCallKeep.removeEventListener('answerCall');
// Open Closed App or bring to the foreground
RNCallKeep.backToForeground();
// Dismiss Incoming Call screen UI
RNCallKeep.endCall(data.callUUID);
// Save payload in localstorage or whatever you prefer
// so that we can access it from inside the app later
AsyncStorage.setItem('answerCall_data', JSON.stringify(data));
});
}
});
When the App starts, fetch if any data is available for the incoming call, for our case, we saved "room code" data in AsyncStorage
by the answerCall_data
key.
If no data is present for the answerCall_data
key, then the app can continue the normal flow, otherwise, you can show directly show "Meeting screen"
to the user and pass the fetched "room code" to the "Meeting screen".
You can check out how we handled App UI in the app here
// Sudo Code for Handling App UI logic
// Fetch data from AsyncStorage
const data = await AsyncStorage.getItem('answerCall_data');
// If roomCode data is found, render MeetingScreen
// Clear roomCode data
if (data.roomCode) {
return <MeetingScreen roomCode={data.roomCode} />
}
// If roomCode data is unavailable, continue the normal flow
return <WelcomeScreen />