React Native CallKeep
React Native CallKeep utilises a brand new iOS 10 framework CallKit and Android ConnectionService to make the life easier for VoIP developers using React Native.
For more information about CallKit on iOS, please see Official CallKit Framework Document or Introduction to CallKit by Xamarin
For more information about ConnectionService on Android, please see Android Documentation and Build a calling app
Demo
A demo of react-native-callkeep
is available in the wazo-react-native-demo repository.
Android
iOS
Installation
npm install --save react-native-callkeep
yarn add react-native-callkeep
Usage
Setup
import RNCallKeep from 'react-native-callkeep';
const options = {
ios: {
appName: 'My app name',
},
android: {
alertTitle: 'Permissions required',
alertDescription: 'This application needs to access your phone accounts',
cancelButton: 'Cancel',
okButton: 'ok',
}
};
RNCallKeep.setup(options);
options
: Object
ios
: object
appName
: string (required)
- It will be displayed on system UI when incoming calls received
imageName
: string (optional)
- If provided, it will be displayed on system UI during the call
ringtoneSound
: string (optional)
- If provided, it will be played when incoming calls received; the system will use the default ringtone if this is not provided
android
: object
alertTitle
: string (required)
When asking for phone account permission, we need to provider a title for the Alert
to ask the user for italertDescription
: string (required)
When asking for phone account permission, we need to provider a description for the Alert
to ask the user for itcancelButton
: string (required)
Cancel button labelokButton
: string (required)
Ok button label
Methods
setAvailable
This feature is available only on Android.
Tell ConnectionService that the device is ready to accept outgoing calls.
If not the user will be stuck in the build UI screen without any actions.
Eg: Call it with false
when disconnected from the sip client, when your token expires ...
RNCallKeep.setAvailable(true);
active
: boolean
- Tell whenever the app is ready or not
displayIncomingCall
Display system UI for incoming call
RNCallKeep.displayIncomingCall(uuid, handle);
uuid
: string
- An
uuid
that should be stored and re-used for stopCall
.
handle
: string
- Phone number of the caller
localizedCallerName
: string (optional, iOS only)
- Name of the caller to be displayed on the native UI
handleType
: string (optional, iOS only)
generic
number
(default)email
hasVideo
: boolean (optional, iOS only)
false
(default)true
(you know... when not false)
startCall
When you make an outgoing call, tell the device that a call is occurring.
This feature is available only on iOs.
RNCallKeep.startCall(uuid, number);
- uuid: string
- An
uuid
that should be stored and re-used for stopCall
.
handle
: string
- Phone number of the callee
handleType
: string (optional, iOS only)
generic
number
(default)email
hasVideo
: boolean (optional, iOS only)
false
(default)true
(you know... when not false)
contactIdentifier
: string (optional)
- The identifier is displayed in the native call UI, and is typically the name of the call recipient.
endCall
When you finish an incoming/outgoing call.
RNCallKeep.endCall(uuid);
uuid
: string
- The
uuid
used for startCall
or displayIncomingCall
setCurrentCallActive
Mark the current call as active (eg: when the callee as answered).
RNCallKeep.setCurrentCallActive();
setMutedCall
Switch the mic on/off.
This feature is available only on iOs.
RNCallKeep.setMutedCall(uuid, true);
uuid
: string
- uuid of the current call.
muted
: boolean
checkIfBusy
Checks if there are any active calls on the device and returns a promise with a boolean value (true
if there're active calls, false
otherwise).
This feature is available only on iOs.
RNCallKeep.checkIfBusy();
checkSpeaker
Checks if the device speaker is on and returns a promise with a boolean value (true
if speaker is on, false
otherwise).
This feature is available only on iOs.
RNCallKeep.checkSpeaker();
supportConnectionService (async)
Tells if ConnectionService
is available on the device (returns a boolean).
This feature is available only on Android.
RNCallKeep.supportConnectionService();
hasPhoneAccount (async)
Checks if the user has enabled the phone account for your application.
A phone account must be enable to be able to display UI screen on incoming call and make outgoing calls from native Contact application.
Returns a promise of a boolean.
This feature is available only on Android.
await RNCallKeep.hasPhoneAccount();
hasDefaultPhoneAccount
Checks if the user has set a default phone account.
If the user has not set a default they will be prompted to do so with an alert.
This is a workaround for an issue affecting some Samsung devices.
This feature is available only on Android.
const options = {
alertTitle: 'Default not set',
alertDescription: 'Please set the default phone account'
};
RNCallKeep.hasDefaultPhoneAccount(options);
Events
didReceiveStartCallAction
User start call action from Recents (Or Contact on Android) in built-in phone app.
Try to start your call action from here (e.g. get credentials of the user by data.handle
and/or send INVITE to your SIP server)
After all works are done, remember to call RNCallKeep.startCall(uuid, calleeNumber)
RNCallKeep.addEventListener('didReceiveStartCallAction', ({ handle }) => {
});
handle
(string)
- The number/name got from Recents in built-in Phone app
- answerCall
User answer the incoming call
RNCallKeep.addEventListener('answerCall', ({ callUUID }) => {
});
callUUID
(string)
- The UUID of the call that is to be answered (iOS only).
- endCall
User finish the call.
RNCallKeep.addEventListener('endCall', ({ callUUID }) => {
});
callUUID
(string)
- The UUID of the call that is to be answered (iOS only).
- didActivateAudioSession
The AudioSession
has been activated by RNCallKeep.
RNCallKeep.addEventListener('didActivateAudioSession', () => {
});
- didDisplayIncomingCall
Callback for RNCallKeep.displayIncomingCall
RNCallKeep.addEventListener('didDisplayIncomingCall', ({ error }) => {
});
- didPerformSetMutedCallAction
A call was muted by the system or the user:
RNCallKeep.addEventListener('didPerformSetMutedCallAction', (muted) => {
});
- didToggleHoldCallAction
A call was held or unheld by the current user
RNCallKeep.addEventListener('didToggleHoldCallAction', ({ hold, callUUID }) => {
});
hold
(boolean)callUUID
(string)
- The UUID of the call that is to be answered (iOS only).
- didPerformDTMFAction
Used type a number on his dialer
RNCallKeep.addEventListener('didPerformDTMFAction', ({ dtmf, callUUID }) => {
});
dtmf
(string)callUUID
(string)
Example
A full example is available in the wazo-react-native-demo repository.
import React from 'react';
import RNCallKeep from 'react-native-callkeep';
import uuid from 'uuid';
class RNCallKeepExample extends React.Component {
constructor(props) {
super(props);
this.currentCallId = null;
const options = {
ios: {
appName: 'WazoReactNativeDemo',
},
android: {
alertTitle: 'Permissions required',
alertDescription: 'This application needs to access your phone accounts',
cancelButton: 'Cancel',
okButton: 'ok',
}
};
try {
RNCallKeep.setup(options);
RNCallKeep.setAvailable(true);
} catch (err) {
console.error('initializeCallKeep error:', err.message);
}
RNCallKeep.addEventListener('didReceiveStartCallAction', this.onNativeCall);
RNCallKeep.addEventListener('answerCall', this.onAnswerCallAction);
RNCallKeep.addEventListener('endCall', this.onEndCallAction);
RNCallKeep.addEventListener('didDisplayIncomingCall', this.onIncomingCallDisplayed);
RNCallKeep.addEventListener('didPerformSetMutedCallAction', this.onToggleMute);
RNCallKeep.addEventListener('didActivateAudioSession', this.audioSessionActivated);
}
onNativeCall = ({ handle }) => {
RNCallKeep.startCall(this.getCurrentCallId(), handle);
};
onAnswerCallAction = ({ callUUID }) => {
};
onEndCallAction = ({ callUUID }) => {
RNCallKeep.endCall(this.getCurrentCallId());
this.currentCallId = null;
};
onIncomingCallDisplayed = error => {
};
onToggleMute = (muted) => {
};
audioSessionActivated = (data) => {
};
getCurrentCallId = () => {
if (!this.currentCallId) {
this.currentCallId = uuid.v4();
}
return this.currentCallId;
};
render() {
}
}
Notes
- On iOS, you should call
setup
each time you want to use callKeep.
Contributing
Any pull request, issue report and suggestion are highly welcome!
License
This work is dual-licensed under ISC and MIT.
Previous work done by @ianlin on iOS is on ISC Licence.
We choose MIT for the rest of the project.
SPDX-License-Identifier: ISC OR MIT