Research
Security News
Malicious npm Package Targets Solana Developers and Hijacks Funds
A malicious npm package targets Solana developers, rerouting funds in 2% of transactions to a hardcoded address.
react-native-callkeep
Advanced tools
iOS 10 CallKit and Android ConnectionService Framework For React Native
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
A demo of react-native-callkeep
is available in the wazo-react-native-demo repository.
npm install --save react-native-callkeep
# or
yarn add react-native-callkeep
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',
imageName: 'phone_account_icon',
additionalPermissions: [PermissionsAndroid.PERMISSIONS.example]
}
};
RNCallKeep.setup(options);
options
: Object
ios
: object
appName
: string (required)
It will be displayed on system UI when incoming calls receivedimageName
: string (optional)
If provided, it will be displayed on system UI during the callringtoneSound
: string (optional)
If provided, it will be played when incoming calls received; the system will use the default ringtone if this is not providedmaximumCallGroups
: string (optional)
If provided, the maximum number of call groups supported by this application (Default: 3)maximumCallsPerCallGroup
: string (optional)
If provided, the maximum number of calls in a single group, used for conferencing (Default: 1, no conferencing)supportsVideo
: boolean (optional)
If provided, whether or not the application supports video calling (Default: true)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 labelimageName
: string (optional)
The image to use in the Android Phone application's native UI for enabling/disabling calling accounts. Should be a 48x48 HDPI
grayscale PNG image. Must be in your drawable resources for the parent application. Must be lowercase and underscore (_) characters
only, as Java doesn't like capital letters on resources.additionalPermissions
: [PermissionsAndroid] (optional)
Any additional permissions you'd like your app to have at first launch. Can be used to simplify permission flows and avoid
multiple popups to the user at different times.This feature is available only on Android.
Tell ConnectionService that the device is ready to make outgoing calls via the native Phone app.
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, when your user log out ...
Eg: When your used log out (or the connection to your server is broken, etc..), you have to call setAvailable(false)
so CallKeep will refuse the call and your user will not be stuck in the native UI.
RNCallKeep.setAvailable(true);
active
: boolean
This feature is available only on Android.
Mark the current call as active (eg: when the callee has answered). Necessary to set the correct Android capabilities (hold, mute) once the call is set as active. Be sure to set this only after your call is ready for two way audio; used both incoming and outgoing calls.
RNCallKeep.setCurrentCallActive(uuid);
uuid
: string
uuid
used for startCall
or displayIncomingCall
Display system UI for incoming calls
RNCallKeep.displayIncomingCall(uuid, handle, localizedCallerName);
uuid
: string
uuid
that should be stored and re-used for stopCall
.handle
: string
localizedCallerName
: string (optional)
handleType
: string (optional, iOS only)
generic
number
(default)email
hasVideo
: boolean (optional, iOS only)
false
(default)true
(you know... when not false)This feature is available only on Android.
Use this to tell the sdk a user answered a call from the app UI.
RNCallKeep.answerIncomingCall(uuid)
uuid
: string
uuid
used for startCall
or displayIncomingCall
When you make an outgoing call, tell the device that a call is occurring. The argument list is slightly different on iOS and Android:
iOS:
RNCallKeep.startCall(uuid, handle, contactIdentifier, handleType, hasVideo);
Android:
RNCallKeep.startCall(uuid, handle, contactIdentifier);
uuid
: string
uuid
that should be stored and re-used for stopCall
.handle
: string
contactIdentifier
: string
handleType
: string (optional, iOS only)
generic
number
(default)email
hasVideo
: boolean (optional, iOS only)
false
(default)true
(you know... when not false)This feature is available only on Android.
Sets the Android caller name and number Use this to update the Android display after an outgoing call has started
RNCallKeep.updateDisplay(uuid, displayName, handle)
uuid
: string
uuid
used for startCall
or displayIncomingCall
displayName
: string (optional)
handle
: string
When you finish an incoming/outgoing call.
RNCallKeep.endCall(uuid);
uuid
: string
uuid
used for startCall
or displayIncomingCall
End all ongoing connections.
RNCallKeep.endAllCalls();
When you reject an incoming call.
RNCallKeep.rejectCall(uuid);
uuid
: string
uuid
used for startCall
or displayIncomingCall
Report that the call ended without the user initiating
RNCallKeep.reportEndCallWithUUID(uuid, reason);
uuid
: string
uuid
used for startCall
or displayIncomingCall
reason
: int
CXCallEndedReason
constants used for iOS. DisconnectCause
used for Android.END_CALL_REASON = {
failed: 1,
remoteEnded: 2,
unanswered: 3
}
Switch the mic on/off.
RNCallKeep.setMutedCall(uuid, true);
uuid
: string
muted
: booleanSet a call on/off hold.
RNCallKeep.setOnHold(uuid, true)
uuid
: string
hold
: booleanEnd all calls that have been started on the device.
RNCallKeep.endAllCalls();
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();
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();
Tells if ConnectionService
is available on the device (returns a boolean).
This feature is available only on Android.
RNCallKeep.supportConnectionService();
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();
This feature is available only on Android, useful when waking up the application for an outgoing call.
When waking up the Android application in background mode (eg: when the application is killed and the user make a call from the native Phone application).
The user can hang up the call before your application has been started in background mode, and you can lost the RNCallKeepPerformEndCallAction
event.
To be sure that the outgoing call is still here, you can call hasOutgoingCall
when you app waken up.
const hasOutgoingCall = await RNCallKeep.hasOutgoingCall();
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);
Device sends this event once it decides the app is allowed to start a call, either from the built-in phone screens (iOS/Recents, Android/Contact),
or by the app calling RNCallKeep.startCall
.
Try to start your app call action from here (e.g. get credentials of the user by data.handle
and/or send INVITE to your SIP server)
Note: on iOS callUUID
is not defined as the call is not yet managed by CallKit. You have to generate your own and call startCall
.
RNCallKeep.addEventListener('didReceiveStartCallAction', ({ handle, callUUID, name }) => {
});
handle
(string)
callUUID
(string)
name
(string)
User answer the incoming call
RNCallKeep.addEventListener('answerCall', ({ callUUID }) => {
// Do your normal `Answering` actions here.
});
callUUID
(string)
User finish the call.
RNCallKeep.addEventListener('endCall', ({ callUUID }) => {
// Do your normal `Hang Up` actions here
});
callUUID
(string)
The AudioSession
has been activated by RNCallKeep.
RNCallKeep.addEventListener('didActivateAudioSession', () => {
// you might want to do following things when receiving this event:
// - Start playing ringback if it is an outgoing call
});
Callback for RNCallKeep.displayIncomingCall
RNCallKeep.addEventListener('didDisplayIncomingCall', ({ error, uuid, handle, localizedCallerName, fromPushKit }) => {
// you might want to do following things when receiving this event:
// - Start playing ringback if it is an outgoing call
});
error
(string)
A call was muted by the system or the user:
RNCallKeep.addEventListener('didPerformSetMutedCallAction', ({ muted, callUUID }) => {
});
muted
(boolean)callUUID
(string)
A call was held or unheld by the current user
RNCallKeep.addEventListener('didToggleHoldCallAction', ({ hold, callUUID }) => {
});
hold
(boolean)callUUID
(string)
Used type a number on his dialer
RNCallKeep.addEventListener('didPerformDTMFAction', ({ digits, callUUID }) => {
});
digits
(string)
callUUID
(string)
A full example is available in the example folder.
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;
// Add RNCallKeep Events
RNCallKeep.addEventListener('didReceiveStartCallAction', this.didReceiveStartCallAction);
RNCallKeep.addEventListener('answerCall', this.onAnswerCallAction);
RNCallKeep.addEventListener('endCall', this.onEndCallAction);
RNCallKeep.addEventListener('didDisplayIncomingCall', this.onIncomingCallDisplayed);
RNCallKeep.addEventListener('didPerformSetMutedCallAction', this.onToggleMute);
RNCallKeep.addEventListener('didToggleHoldCallAction', this.onToggleHold);
RNCallKeep.addEventListener('didPerformDTMFAction', this.onDTMFAction);
RNCallKeep.addEventListener('didActivateAudioSession', this.audioSessionActivated);
}
// Initialise RNCallKeep
setup = () => {
const options = {
ios: {
appName: 'ReactNativeWazoDemo',
imageName: 'sim_icon',
supportsVideo: false,
maximumCallGroups: '1',
maximumCallsPerCallGroup: '1'
},
android: {
alertTitle: 'Permissions Required',
alertDescription:
'This application needs to access your phone calling accounts to make calls',
cancelButton: 'Cancel',
okButton: 'ok',
imageName: 'sim_icon',
additionalPermissions: [PermissionsAndroid.PERMISSIONS.READ_CONTACTS]
}
};
try {
RNCallKeep.setup(options);
RNCallKeep.setAvailable(true); // Only used for Android, see doc above.
} catch (err) {
console.error('initializeCallKeep error:', err.message);
}
}
// Use startCall to ask the system to start a call - Initiate an outgoing call from this point
startCall = ({ handle, localizedCallerName }) => {
// Your normal start call action
RNCallKeep.startCall(this.getCurrentCallId(), handle, localizedCallerName);
};
reportEndCallWithUUID = (callUUID, reason) => {
RNCallKeep.reportEndCallWithUUID(callUUID, reason);
}
// Event Listener Callbacks
didReceiveStartCallAction(data) => {
let { handle, callUUID, name } = data;
// Get this event after the system decides you can start a call
// You can now start a call from within your app
};
onAnswerCallAction = (data) => {
let { callUUID } = data;
// Called when the user answers an incoming call
};
onEndCallAction = (data) => {
let { callUUID } = data;
RNCallKeep.endCall(this.getCurrentCallId());
this.currentCallId = null;
};
// Currently iOS only
onIncomingCallDisplayed = (data) => {
let { error } = data;
// You will get this event after RNCallKeep finishes showing incoming call UI
// You can check if there was an error while displaying
};
onToggleMute = (data) => {
let { muted, callUUID } = data;
// Called when the system or user mutes a call
};
onToggleHold = (data) => {
let { hold, callUUID } = data;
// Called when the system or user holds a call
};
onDTMFAction = (data) => {
let { digits, callUUID } = data;
// Called when the system or user performs a DTMF action
};
audioSessionActivated = (data) => {
// you might want to do following things when receiving this event:
// - Start playing ringback if it is an outgoing call
};
getCurrentCallId = () => {
if (!this.currentCallId) {
this.currentCallId = uuid.v4();
}
return this.currentCallId;
};
render() {
}
}
In some case your application can be unreachable :
To be able to wake up your application to display the incoming call, you can use https://github.com/ianlin/react-native-voip-push-notification on iOS or BackgroundMessaging from react-native-firebase-(Optional)(Android-only)-Listen-for-FCM-messages-in-the-background).
You have to send a push to your application, like with Firebase for Android and with a library supporting PushKit pushes for iOS.
Since iOS 13, you'll have to report the incoming calls that wakes up your application, like in your AppDelegate.m
:
- (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(PKPushType)type withCompletionHandler:(void (^)(void))completion {
// Process the received push
[RNVoipPushNotificationManager didReceiveIncomingPushWithPayload:payload forType:(NSString *)type];
// Retrieve information like handle and callerName here
[RNCallKeep reportNewIncomingCall:uuid handle:handle handleType:@"generic" hasVideo:false localizedCallerName:callerName fromPushKit: YES];
completion();
}
adb logcat *:S RNCallKeepModule:V
Any pull request, issue report and suggestion are highly welcome!
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
FAQs
iOS 10 CallKit and Android ConnectionService Framework For React Native
The npm package react-native-callkeep receives a total of 3,891 weekly downloads. As such, react-native-callkeep popularity was classified as popular.
We found that react-native-callkeep demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
A malicious npm package targets Solana developers, rerouting funds in 2% of transactions to a hardcoded address.
Security News
Research
Socket researchers have discovered malicious npm packages targeting crypto developers, stealing credentials and wallet data using spyware delivered through typosquats of popular cryptographic libraries.
Security News
Socket's package search now displays weekly downloads for npm packages, helping developers quickly assess popularity and make more informed decisions.