Install & Compatibility
Where this runs
tested against v? · npm install
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
muslnode 18–226 runs
build_error
glibcnode 18–226 runs
build_error
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
RNCallKeep
✓ import RNCallKeep from 'react-native-callkeep';
✗ const RNCallKeep = require('react-native-callkeep');
The library primarily exports RNCallKeep as a default export. While CommonJS `require` might work in some transpiled environments, `import` is the idiomatic and recommended approach in modern React Native projects, especially for type inference.
PermissionsAndroid
✓ import { PermissionsAndroid } from 'react-native';
✗ import PermissionsAndroid from 'react-native';
PermissionsAndroid is a named export from the `react-native` core library, often used in conjunction with CallKeep for requesting necessary phone permissions on Android.
UUID generation
✓ import { v4 as uuidv4 } from 'uuid'; // or other UUID library
const callUUID = uuidv4();
✗ const callUUID = 'some-static-string-id';
For `displayIncomingCall` and other call management functions, a valid UUID is crucial. Using a static string or invalid format will prevent incoming call screens from being shown on iOS.
This quickstart initializes React Native CallKeep, configures it for both iOS CallKit and Android ConnectionService with proper permissions and foreground service setup, and demonstrates how to display an incoming call. It includes UUID generation as a best practice.
import RNCallKeep from 'react-native-callkeep';
import { PermissionsAndroid, Platform } from 'react-native';
import 'react-native-get-random-values'; // Polyfill for crypto for UUID generation
import { v4 as uuidv4 } from 'uuid'; // Recommended UUID library
const setupCallKeep = async () => {
const options = {
ios: {
appName: 'My VoIP App',
imageName: 'callkeep_icon', // Optional: image for system UI
maximumCallGroups: 1,
maximumCallsPerCallGroup: 1,
supportsVideo: false,
includesCallsInRecents: true, // Show calls in iOS Recents list
},
android: {
alertTitle: 'Permissions required',
alertDescription: 'This application needs to access your phone accounts to manage calls and show caller ID.',
cancelButton: 'Cancel',
okButton: 'Ok',
imageName: 'phone_account_icon', // Make sure this icon exists in your drawable folder
additionalPermissions: [
PermissionsAndroid.PERMISSIONS.READ_PHONE_STATE,
PermissionsAndroid.PERMISSIONS.CALL_PHONE,
...(Platform.Version >= 31 ? [PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT] : []), // For Android 12+ Bluetooth
],
foregroundService: {
channelId: 'com.mycompany.myapp.callservice',
channelName: 'VoIP Call Service',
notificationTitle: 'My VoIP App is running in the background for calls',
notificationIcon: 'ic_launcher_round', // Ensure this icon exists in your Android resources
},
selfManaged: false, // Set to true for custom incoming call UI on Android
// Additional Android 13+ foreground service permissions
// 'android.permission.FOREGROUND_SERVICE_PHONE_CALL',
},
};
try {
// Request necessary Android permissions before setup
if (Platform.OS === 'android') {
const granted = await PermissionsAndroid.requestMultiple(options.android.additionalPermissions);
const allGranted = Object.values(granted).every(status => status === PermissionsAndroid.RESULTS.GRANTED);
if (!allGranted) {
console.warn('CallKeep permissions not fully granted.');
// You might want to show an alert or prevent app functionality here
return;
}
}
const accepted = await RNCallKeep.setup(options);
if (accepted) {
console.log('RNCallKeep setup successfully.');
// Example: Register an event listener for answering calls
RNCallKeep.addEventListener('answerCall', ({ callUUID }) => {
console.log(`Call ${callUUID} answered.`);
// Implement your logic to connect the call
});
// Other event listeners like 'endCall', 'setMutedCall', etc.
} else {
console.warn('RNCallKeep setup was not accepted by the user or failed.');
}
} catch (err: any) {
console.error('Error setting up RNCallKeep:', err.message);
}
};
// Call the setup function when your app initializes, e.g., in your App.js root component's useEffect
// useEffect(() => { setupCallKeep(); }, []);
// Example of displaying an incoming call (after setup)
const displayExampleIncomingCall = (callerName: string) => {
const currentCallUUID = uuidv4();
RNCallKeep.displayIncomingCall(
currentCallUUID,
'remote-caller-id-123',
callerName,
'Generic',
true, // hasVideo
);
console.log(`Displayed incoming call from ${callerName} with UUID: ${currentCallUUID}`);
return currentCallUUID;
};
// To simulate an incoming call (for testing, after setup is complete):
// const activeCallId = displayExampleIncomingCall('Jane Doe');
// To end the call (e.g., after 30 seconds):
// setTimeout(() => { RNCallKeep.endCall(activeCallId); }, 30000);
Errors
Common errors & fixes
CallKit/ConnectionService not working / Incoming call screen not showing on device.
The library's core features rely on native device capabilities not present in emulators/simulators, or an invalid UUID was provided.
fixTest the application on a physical iOS or Android device. Ensure a valid, unique UUID is generated and passed to `displayIncomingCall`.
Android app crashes or behaves unexpectedly after permissions are denied, or when app is in background/killed state.
Insufficient or improperly handled Android permissions, or the foreground service for background operation is not correctly configured.
fixVerify that all required permissions are declared in `AndroidManifest.xml` and requested at runtime via `PermissionsAndroid`. For Android 11+, ensure the `foregroundService` options are correctly set in `RNCallKeep.setup()`.
Error: 'camera|microphone' is incompatible with attribute foregroundServiceType (attr) flags [...]
Incorrect `foregroundServiceType` flags specified in `AndroidManifest.xml` (or inferred by newer Android SDK versions) that conflict with CallKeep's use of foreground services.
fixCheck your `AndroidManifest.xml` for `FOREGROUND_SERVICE` declarations and ensure they align with the expected types. Review `react-native-callkeep` documentation or migration guides for the correct `foregroundServiceType` flags, which often include `phoneCall` and possibly `microphone`.
TypeError: RNCallKeep.setup is not a function (or 'undefined is not an object (evaluating 'RNCallKeep.setup')')
The native module is not correctly linked with the React Native bridge, or a Metro cache issue.
fixRun `npx pod-install` in your `ios` directory, `npm install` or `yarn install`, then clear Metro cache (`npm start --reset-cache`). Verify manual linking steps for older React Native versions if automatic linking fails.
On Android, after answering a call, the app goes to the background, but the CallKeep UI remains on top or the app doesn't come to the foreground.
This is a common behavior/issue with `ConnectionService` on some Android versions where the native call UI can override the app's foregrounding logic.
fixFor versions of Android where this is problematic, you might need to manually bring the app to the foreground after answering, potentially using a combination of `backToForeground()` if exposed by CallKeep, or external libraries like `react-native-incall-manager` or `react-native-background-actions` to manage app state more aggressively. Ensure `selfManaged: false` is set in your setup unless you intend to provide a fully custom UI.
Audit
Dependencies
react-nativerequiredPeer dependency for core React Native functionalities and bridging.