iOS CallKit framework and Android ConnectionService for React Native

Overview

React Native CallKeep

npm version npm downloads

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

⚠️ CallKit and ConnectionService are only available on real devices, this library will not work on simulators.

Summary

Demo

A demo of react-native-callkeep is available in the wazo-react-native-demo repository.

Android

Connection Service

iOS

Connection Service

Installation

npm install --save react-native-callkeep
# or
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',
    imageName: 'phone_account_icon',
    additionalPermissions: [PermissionsAndroid.PERMISSIONS.example],
    // Required to get audio in background when using Android 11
    foregroundService: {
      channelId: 'com.company.my',
      channelName: 'Foreground service for my app',
      notificationTitle: 'My app is running on background',
      notificationIcon: 'Path to the resource icon of the notification',
    }, 
  }
};

RNCallKeep.setup(options).then(accepted => {});

iOS only.

Alternative on iOS you can perform setup in AppDelegate.m. Doing this allows capturing events prior to the react native event bridge being up. Please be aware that calling setup in AppDelegate.m will ignore any subsequent calls to RNCallKeep.setup();.

@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{ 
  self.bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];

  [RNCallKeep setup:@{
    @"appName": @"Awesome App",
    @"maximumCallGroups": @3,
    @"maximumCallsPerCallGroup": @1,
    @"supportsVideo": @NO,
  }];

  RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:self.bridge
                                                   moduleName:@"App"
                                            initialProperties:nil];

  // ======== OTHER CODE REDACTED ==========

  return YES;
}
  • 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
      • includesCallsInRecents: boolean (optional) If provided, calls will be shown in the recent calls when true and not when false (ios 11 and above) (Default: true)
      • maximumCallGroups: 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 it
      • alertDescription: string (required) When asking for phone account permission, we need to provider a description for the Alert to ask the user for it
      • cancelButton: string (required) Cancel button label
      • okButton: string (required) Ok button label
      • imageName: 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.
      • selfManaged: boolean (optional) When set to true, call keep will configure itself to run as a self managed connection service. This is an advanced topic, and it's best to refer to Googles Documentation on the matter.

setup calls internally registerPhoneAccount and registerEvents.

Constants

To make passing the right integer into methods easier, there are constants that are exported from the module.

const CONSTANTS = {
  END_CALL_REASONS: {
    FAILED: 1,
    REMOTE_ENDED: 2,
    UNANSWERED: 3,
    ANSWERED_ELSEWHERE: 4,
    DECLINED_ELSEWHERE: 5,
    MISSED: 6
  }
};

const { CONSTANTS as CK_CONSTANTS, RNCallKeep } from 'react-native-callkeep';

console.log(CK_CONSTANTS.END_CALL_REASONS.FAILED) // outputs 1

Android Self Managed Mode

This feature is available only on Android.

Android supports calling apps running in what's called "Self Managed". This means the apps are able (and required) to provide their own UI for managing calls. This includes both in call UI elements and incoming call notification UI. This method is all or nothing. You can't mix partial elements, such as having a custom in call view, but use the default incoming call UI.

To implement a self managed calling app, the following steps are necessary:

  • Set selfManaged: true in setup.
  • On an incoming call, from react native, call RNCallKeep.displayIncomingCall
  • CallKeep will then fire the showIncomingCallUi event.
  • When showIncomingCallUi is fired, you must show an incoming call UI. This would be a high priority notification (Android: Display time-sensitive notifications).
  • If the user answers the call, you call the appropriate RNCallKeep actions such as answerCall or endCall

Self Managed calling apps are an advanced topic, and there are many steps involved in implementing them, but here are some things to keep in mind:

  • React Native Headless Tasks are a great way to execute React Native code. Remember to start up the headless task as a Foreground Service.
  • Android will deprioritize your high priority FCM notifications if you fail to show an incoming call ui when receiving them.
  • You can avoid getting flooded with sticky foreground service notifications by not defining a Foreground Service for CallKeep, and instead managing this on your own.

⚠️ To be able to use the self managed mode, you'll have to add the READ_CALL_LOG permission in your android/src/main/AndroidManifest.xml file:

">

  

API

Method Return Type iOS Android
getInitialEvents() Promise
setAvailable() Promise
setForegroundServiceSettings() Promise
canMakeMultipleCalls() Promise
setCurrentCallActive() Promise
isCallActive() Promise
getCalls() Promise
displayIncomingCall() Promise
answerIncomingCall() Promise
startCall() Promise
updateDisplay() Promise
endCall() Promise
endAllCalls() Promise
rejectCall() Promise
reportEndCallWithUUID() Promise
setMutedCall() Promise
setOnHold() Promise
checkIfBusy() Promise
checkSpeaker() Promise
toggleAudioRouteSpeaker() Promise
supportConnectionService() Promise
hasPhoneAccount() Promise
hasOutgoingCall() Promise
hasDefaultPhoneAccount() Promise
checkPhoneAccountEnabled() Promise
isConnectionServiceAvailable() Promise
backToForeground() Promise
removeEventListener() void
registerPhoneAccount() void
registerAndroidEvents() void

getInitialEvents

This feature is available only on iOS.

If there were some actions performed by user before JS context has been created, this method would return early fired events. This is alternative to "didLoadWithEvents" event.

RNCallKeep.getInitialEvents();

setAvailable

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);

setForegroundServiceSettings

This feature is available only on Android.

Configures the Foreground Service used for Android 11 to get microphone access on background. Similar to set the foregroundService key in the setup() method.

RNCallKeep.setForegroundServiceSettings({
    channelId: 'com.company.my',
    channelName: 'Foreground service for my app',
    notificationTitle: 'My app is running on background',
    notificationIcon: 'Path to the resource icon of the notification',
});

canMakeMultipleCalls

This feature is available only on Android.

Disable the "Add call" button in ConnectionService UI.

RNCallKeep.canMakeMultipleCalls(false); // Enabled by default
  • active: boolean
    • Tell whether the app is ready or not

setCurrentCallActive

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
    • The uuid used for startCall or displayIncomingCall

isCallActive

This feature is available only on IOS.

Returns true if the UUID passed matches an existing and answered call. This will return true ONLY if the call exists and the user has already answered the call. It will return false if the call does not exist or has not been answered. This is exposed to both React Native and Native sides. This was exposed so a call can be canceled if ringing and the user answered on a different device.

RNCallKeep.isCallActive(uuid);
  • uuid: string
    • The uuid used for startCall or displayIncomingCall

getCalls

This feature is available only on IOS.

Returns a Promise. The result will be an array with all current calls and their states.

RNCallKeep.getCalls();

response:
[{
  callUUID: "E26B14F7-2CDF-48D0-9925-532199AE7C48",
  hasConnected: true,
  hasEnded: false,
  onHold: false,
  outgoing: false,
}]

displayIncomingCall

Display system UI for incoming calls

RNCallKeep.displayIncomingCall(uid, handle, localizedCallerName = '', handleType = 'number', hasVideo = false, options = null);
  • uuid: string
    • An uuid that should be stored and re-used for stopCall.
  • handle: string
    • Phone number of the caller
  • localizedCallerName: string (optional)
    • 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)
  • options: object (optional)
    • ios: object
      • supportsHolding: boolean (optional, default true)
      • supportsDTMF: boolean (optional, default true)
      • supportsGrouping: boolean (optional, default true)
      • supportsUngrouping: boolean (optional, default true)
    • android: object (currently no-op)

answerIncomingCall

Use this to tell the sdk a user answered a call from the app UI.

RNCallKeep.answerIncomingCall(uuid)
  • uuid: string
    • The uuid used for startCall or displayIncomingCall

startCall

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
    • An uuid that should be stored and re-used for stopCall.
  • handle: string
    • Phone number of the callee
  • contactIdentifier: string
    • The identifier is displayed in the native call UI, and is typically the name of the call recipient.
  • handleType: string (optional, iOS only)
    • generic
    • number (default)
    • email
  • hasVideo: boolean (optional, iOS only)
    • false (default)
    • true (you know... when not false)

updateDisplay

Use this to update the display after an outgoing call has started.

RNCallKeep.updateDisplay(uuid, displayName, handle)
  • uuid: string
    • The uuid used for startCall or displayIncomingCall
  • displayName: string (optional)
    • Name of the caller to be displayed on the native UI
  • handle: string
    • Phone number of the caller
  • options: object (optional)
    • ios: object
      • hasVideo: boolean (optional)
      • supportsHolding: boolean (optional)
      • supportsDTMF: boolean (optional)
      • supportsGrouping: boolean (optional)
      • supportsUngrouping: boolean (optional)
    • android: object (currently no-op)

endCall

When finish an incoming/outgoing call.
(When user actively chooses to end the call from your app's UI.)

RNCallKeep.endCall(uuid);
  • uuid: string
    • The uuid used for startCall or displayIncomingCall

endAllCalls

End all ongoing calls.

RNCallKeep.endAllCalls();

rejectCall

When you reject an incoming call.

RNCallKeep.rejectCall(uuid);
  • uuid: string
    • The uuid used for startCall or displayIncomingCall

reportEndCallWithUUID

Report that the call ended without the user initiating.
(Not ended by user, is usually due to the following reasons)

RNCallKeep.reportEndCallWithUUID(uuid, reason);
  • uuid: string
    • The uuid used for startCall or displayIncomingCall
  • reason: int
    • Reason for the end call
      • Call failed: 1
      • Remote user ended call: 2
      • Remote user did not answer: 3
      • Call Answered elsewhere: 4
      • Call declined elsewhere: 5 (on Android this will map to Remote user ended call if you use the constants)
      • Missed: 6 (on iOS this will map to remote user ended call)
    • Access reasons as constants
    const { CONSTANTS as CK_CONSTANTS, RNCallKeep } from 'react-native-callkeep';
    
    RNCallKeep.reportEndCallWithUUID(uuid, CK_CONSTANTS.END_CALL_REASONS.FAILED);

setMutedCall

Switch the mic on/off.

RNCallKeep.setMutedCall(uuid, true);
  • uuid: string
    • uuid of the current call.
  • muted: boolean

setOnHold

Set a call on/off hold.

RNCallKeep.setOnHold(uuid, true)
  • uuid: string
    • uuid of the current call.
  • hold: boolean

checkIfBusy

This feature is available only on IOS.

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).

RNCallKeep.checkIfBusy();

checkSpeaker

This feature is available only on IOS.

Checks if the device speaker is on and returns a promise with a boolean value (true if speaker is on, false otherwise).

RNCallKeep.checkSpeaker();

toggleAudioRouteSpeaker

This feature is available only on Android.

Update the audio route of Audio Service on Android with a routeSpeaker boolean value (true if speaker need on, false otherwise). When Phone call is active, Android control the audio via connection service. so this function help to toggle the audio to Speaker or wired/ear-piece or vice-versa

RNCallKeep.toggleAudioRouteSpeaker(uuid, true);
  • uuid: string
    • uuid of the current call.
  • routeSpeaker: boolean

getAudioRoutes

Get the list of available audio routes. i.e. bluetooth, wired/ear-piece, speaker and phone.

await RNCallKeep.getAudioRoutes(): AudioRoute;
type AudioRoute = {
    name: string,
    type: string
}

setAudioRoute

Set audio route using a route from getAudioRoutes.

await RNCallKeep.setAudioRoute(uuid, routeName);
  • uuid: string
    • uuid of the current call.
  • routeName: String
    • AudioRoute.name.

supportConnectionService (async)

This feature is available only on Android.

Tells if ConnectionService is available on the device (returns a boolean).

RNCallKeep.supportConnectionService();

hasPhoneAccount (async)

This feature is available only on Android.

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.

await RNCallKeep.hasPhoneAccount();

hasOutgoingCall (async)

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();

hasDefaultPhoneAccount

This feature is available only on Android.

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.

const options = {
  alertTitle: 'Default not set',
  alertDescription: 'Please set the default phone account'
};

RNCallKeep.hasDefaultPhoneAccount(options);

checkPhoneAccountEnabled

This feature is available only on Android.

Checks if the user has set a default phone account and it's enabled.

It's useful for custom permission prompts. It should be used in pair with registerPhoneAccount Similar to hasDefaultPhoneAccount but without trigering a prompt if the user doesn't have a phone account.

RNCallKeep.checkPhoneAccountEnabled();

isConnectionServiceAvailable

This feature is available only on Android.

Check if the device support ConnectionService.

RNCallKeep.checkPhoneAccountEnabled();

backToForeground

This feature is available only on Android.

Use this to display the application in foreground if the application was in background state. This method will open the application if it was closed.

RNCallKeep.backToForeground();

removeEventListener

Allows to remove the listener on an event.

RNCallKeep.removeEventListener('checkReachability');

registerPhoneAccount

Registers Android phone account manually, useful for custom permission prompts when you don't want to call setup(). This method is called by setup, if you already use setup you don't need it.

This feature is available only on Android. On iOS you still have to call setup().

RNCallKeep.registerPhoneAccount();

registerAndroidEvents

Registers Android UI events, useful when you don't want to call setup(). This method is called by setup, if you already use setup you don't need it.

This feature is available only on Android. On iOS you still have to call setup().

RNCallKeep.registerAndroidEvents();

Events

Event iOS Android
didReceiveStartCallAction()
answerCall()
endCall()
didActivateAudioSession()
didDisplayIncomingCall()
didPerformSetMutedCallAction()
didToggleHoldCallAction()
didPerformDTMFAction()
didLoadWithEvents()
showIncomingCallUi()
silenceIncomingCall()
checkReachability()

didReceiveStartCallAction

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)
    • Phone number of the callee
  • callUUID (string)
    • The UUID of the call that is to be answered
  • name (string)
    • Name of the callee

- answerCall

User answer the incoming call

RNCallKeep.addEventListener('answerCall', ({ callUUID }) => {
  // Do your normal `Answering` actions here.
});
  • callUUID (string)
    • The UUID of the call that is to be answered.

- endCall

User finish the call.

RNCallKeep.addEventListener('endCall', ({ callUUID }) => {
  // Do your normal `Hang Up` actions here
});
  • callUUID (string)
    • The UUID of the call that is to be ended.

- didActivateAudioSession

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
});

- didDisplayIncomingCall

Callback for RNCallKeep.displayIncomingCall

RNCallKeep.addEventListener('didDisplayIncomingCall', ({ error, callUUID, handle, localizedCallerName, hasVideo, fromPushKit, payload }) => {
  // you might want to do following things when receiving this event:
  // - Start playing ringback if it is an outgoing call
});
  • error (string)
    • iOS only.
  • callUUID (string)
    • The UUID of the call.
  • handle (string)
    • Phone number of the caller
  • localizedCallerName (string)
    • Name of the caller to be displayed on the native UI
  • hasVideo (string)
    • 1 (video enabled)
    • 0 (video not enabled)
  • fromPushKit (string)
    • 1 (call triggered from PushKit)
    • 0 (call not triggered from PushKit)
  • payload (object)
    • VOIP push payload.

- didPerformSetMutedCallAction

A call was muted by the system or the user:

RNCallKeep.addEventListener('didPerformSetMutedCallAction', ({ muted, callUUID }) => {

});
  • muted (boolean)
  • callUUID (string)
    • The UUID of the call.

- 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.

- didPerformDTMFAction

Used type a number on his dialer

RNCallKeep.addEventListener('didPerformDTMFAction', ({ digits, callUUID }) => {

});
  • digits (string)
    • The digits that emit the dtmf tone
  • callUUID (string)
    • The UUID of the call.

- didLoadWithEvents

iOS only.

Called as soon as JS context initializes if there were some actions performed by user before JS context has been created.

Since iOS 13, you must display incoming call on receiving PushKit push notification. But if app was killed, it takes some time to create JS context. If user answers the call (or ends it) before JS context has been initialized, user actions will be passed as events array of this event. Similar situation can happen if user would like to start a call from Recents or similar iOS app, assuming that your app was in killed state.

In order for this event to reliably fire, it's necessary to perform setup in AppDelegate.m

NOTE: You still need to subscribe / handle the rest events as usuall. This is just a helper whcih cache and propagate early fired events if and only if for "the native events which DID fire BEFORE js bridge is initialed", it does NOT mean this will have events each time when the app reopened.

// register `didLoadWithEvents` somewhere early in your app when it is ready to handle callkeep events.

RNCallKeep.addEventListener('didLoadWithEvents', (events) => {
  // `events` is passed as an Array chronologically, handle or ignore events based on the app's logic
  // see example usage in https://github.com/react-native-webrtc/react-native-callkeep/pull/169 or https://github.com/react-native-webrtc/react-native-callkeep/pull/205
});
  • events Array
    • name: string Native event name like: RNCallKeepPerformAnswerCallAction
    • data: object Object with data passed together with specific event so it can be handled in the same way like original event, for example ({ callUUID }) for answerCall event if name is RNCallKeepPerformAnswerCallAction

- showIncomingCallUi

Android only. Self Managed only.

Only when CallKeep is setup to be in self managed mode. Signals that the app must show an incoming call UI. The implementor must either call displayIncomingCall from react native or native android code to make this event fire.

RNCallKeep.addEventListener('showIncomingCallUi', ({ handle, callUUID, name }) => {

});

The following values will match those initially passed to displayIncomingCall

  • handle (string)
    • Phone number of the incoming caller.
  • callUUID (string)
    • The UUID of the call.
  • name (string)
    • Caller Name.

- silenceIncomingCall

Android only. Self Managed only.

Corresponds to the native onSilence event. The implementor should silence the corresponding incoming calls notification sound when and if this event is fired.

RNCallKeep.addEventListener('silenceIncomingCall', ({ handle, callUUID, name }) => {

});

The following values will match those initially passed to silenceIncomingCall

  • handle (string)
    • Phone number of the incoming caller.
  • callUUID (string)
    • The UUID of the call.
  • name (string)
    • Caller Name.

- checkReachability

Android only.

On Android when the application is in background, after a certain delay the OS will close every connection with informing about it. So we have to check if the application is reachable before making a call from the native phone application.

RNCallKeep.addEventListener('checkReachability', () => {
  RNCallKeep.setReachable();
});

Example

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() {
  }
}

Receiving a call when the application is not reachable.

In some case your application can be unreachable :

  • when the user kill the application
  • when it's in background since a long time (eg: after ~5mn the os will kill all connections).

To be able to wake up your application to display the incoming call, you can use https://github.com/react-native-webrtc/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.

PushKit

Since iOS 13, you'll have to report the incoming calls that wakes up your application with a VoIP push. Add this in your AppDelegate.m if you're using VoIP pushes to wake up your application :

- (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
  // NSString *uuid = /* fetch for payload or ... */ [[[NSUUID UUID] UUIDString] lowercaseString];
  // NSString *callerName = @"caller name here";
  // NSString *handle = @"caller number here";
  // NSDictionary *extra = [payload.dictionaryPayload valueForKeyPath:@"custom.path.to.data"]; /* use this to pass any special data (ie. from your notification) down to RN. Can also be `nil` */

  [RNCallKeep reportNewIncomingCall: uuid
                             handle: handle
                         handleType: @"generic"
                           hasVideo: NO
                localizedCallerName: callerName
                    supportsHolding: YES
                       supportsDTMF: YES
                   supportsGrouping: YES
                 supportsUngrouping: YES
                        fromPushKit: YES
                            payload: extra
              withCompletionHandler: completion];
}

Android 11

Since Android 11, your application requires to start a foregroundService in order to access the microphone in background. You'll need to upgrade your compileSdkVersion to 30 to be able to use this feature.

You have to set the foregroundService key in the setup() method and add a foregroundServiceType in the AndroidManifest file.

Debug

Android

adb logcat *:S RNCallKeep:V

Troubleshooting

  • Ensure that you construct a valid uuid by importing the uuid library and running uuid.v4() as shown in the examples. If you don't do this and use a custom string, the incoming call screen will never be shown on iOS.

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

Comments
  • [ios-13] add new class method to report incoming call when receiving voip push

    [ios-13] add new class method to report incoming call when receiving voip push

    With ios 13, apple has changed the flow we handle voip incoming push notification.

    Important On iOS 13.0 and later, incoming Voice over IP calls must be reported when they are received and before this method finishes execution using the CallKit framework, or the system will terminate your app. Repeatedly failing to report calls may prevent your app from receiving any more incoming call notifications.

    pushRegistry(_:didReceiveIncomingPushWith:for:completion:)

    I added new class method to report incoming call when there is new voip push

    - (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(NSString *)type {
      [RNVoipPushNotificationManager didReceiveIncomingPushWithPayload:payload forType:(NSString *)type];
    
      NSString *uuid = [payload.dictionaryPayload valueForKey:@"uuid"];
      NSString *callerName = [payload.dictionaryPayload valueForKey:@"fromUserName"];
      [RNCallKeep reportNewIncomingCall:uuid handle:@"hadle" handleType:@"generic" hasVideo:true localizedCallerName:callerName];
    }
    
    opened by r0b0t3d 42
  • Implemented self managed mode support for Android

    Implemented self managed mode support for Android

    Implements support for running android in self managed mode. I've performed the implementation in a way that shouldn't change any behavior unless selfManaged is explicitly defined in RNCallKeep.setup():

     RNCallKeep.setup({
      android: {
        alertTitle: 'Permissions required',
        alertDescription: 'This application needs to access your phone accounts',
        cancelButton: 'Cancel',
        okButton: 'OK',
        imageName: 'iconmask',
        selfManaged: true, // <- Enables self managed mode
        additionalPermissions: [],
      },
    });
    

    I've purposely not added any changes to the documentation yet - I feel like it would be better to do so after we've decided on if we're going to take this PR.

    Reviewing and Testing this PR It is anything but trivial to provide an example app for this, but I recommend performing these tests:

    1. Verify that all functionality works as expected when selfManaged is NOT enabled.
    2. In selfManaged mode, verify that showIncomingCallUi is fired in response to RNCallKeep.displayIncomingCall

    The essence of this feature is just to make RNCallKeep deliver the showIncomingCallUi event to react native.

    A summary of changes

    1. Added showIncomingCallUi do the device emitter. This event is fired when the onShowIncomingCall() (link) method is called by android on the Connection implementation.
    2. Adjust which permissions are required in RNCallKeepModule.java when running in selfManaged mode.
    3. Changed index.js so it doesn't open phone accounts if running in selfManaged mode.
    4. Added showIncomingCallUi event to index.d.ts

    684d065f-d09e-4ebb-aa92-1e1a7d15d590

    Marked in yellow in this diagram, is the only difference in operating principle of this module when running in self managed mode. At that point, responsibility of handling the UI related to the call falls entirely on the implementing app.

    The app must still call all the relevant RNCK methods, and listen to the relevant events (such as end call, hold call etc.).

    On an incoming call, we eventually execute RNCallKeep.displayIncomingCall(callUuid, callerNumber, callerName); - in turn, if Android deems this appropriate, it'll fire the showIncomingCallUi event, at which point we need code that shows a notification.

    Anyway, let's discuss this wonderful feature!

    Opinion piece on how this should be implemented: I can see from the other PR that was made for a feature - implementation is fairly similar to this one, that there's always talk about weather this works in background state, with the app dead, foreground etc, and I'd like to address some of that.

    Firstly, there are my personal opinions, so we should of course talk about what we recommend for people implementing this.

    But one prevailing fact remains, and that is that every app has individual implementation quirks around the sip stack, how it's implemented, what their infrastructure is capable of and all that - all of which means that this feature shouldn't be opinionated in nature.

    Battling with stuff like background state, race conditions with initialization of the React Native bridge and so on, are all symptoms of a poor fit into an existing app and it's quirks.

    Now on IOS, because of Apple's requirements to show the ring screen within (2?) seconds, all implementations should converge on doing everything in AppDelegate.m (see my other pull request on that).

    However, on Android we're not as restricted (yet), but we should be prepared for that, and as such not impose a ton of opinion on the implementors.

    But a requirements that FCM does have is that any high priority notification should result in a high priority notification, or they might deprioritize your messages. As such ANY high priority message should, no matter what, invoke RNCallKeep.displayIncomingCall(callUuid, callerNumber, callerName); asap - before even attempting to establish a SIP connection, and then deal with synchronizing this after the fact. And this is the part that'll be extremely different between apps.

    My personal recommandation for implementation, is that people have their own implementation of firebase, that'll immediately launch a headless task in react native, that'll immediately invoke RNCallKeep.displayIncomingCall(callUuid, callerNumber, callerName); - and then start setting up the SIP connection, and converge these based on how the user interacts with the notification that's shown.

    One important thing to know, is that the full screen notification can be done fully in react native - all of which will require some interaction with native android through the native bridge.

    The headless tasks starts incredibly fast, and ensures that we launch the notification fast.

    Libraries like react-native-notifications are unfortunately NOT appropriate for use together with these. They're a recipe for a poor implementation that'll make your apps ability to receive phone calls unreliable. They're too opinionated and hides away too much functionality.

    Even on Android, doing something like this WILL require a fair amount of native implementation to achieve any degree of success. It simply won't work to operate only in React Native land for this.

    A good example of what we're dealing with in other notification libraries, is that they all rely on an event handler to receive device tokens - and googles documentation is extremely clear on the fact that they can distribute a new device token at any point in time. A headless task is the only appropriate way to transport a device token to react native. Event handlers are NOT.

    The immediate example that comes to mind is that Google distributes a new push token while the app is not running - there is no event bridge running, and no new token is stored. A headless task allows native to wake up enough of the react native app to deal with this.

    need review 
    opened by jonastelzio 41
  • Audio not returning after call is resumed

    Audio not returning after call is resumed

    Bug report

    • [ ] I've checked the example to reproduce the issue.

    • Reproduced on:

    • [ ] Android

    • [X] iOS

    Description

    When a call is resumed from a held state I am not getting audio back, unless I use InCallManager to toggle the device speaker.

    Steps to Reproduce

    • Place Call On Hold
    • Hold Call
    • Resume Call

    Versions

    - Callkeep: 3.0.6
    - React Native: 0.59.10
    - iOS: 12.4
    - Android:
    - Phone model: iPhone 8
    
    opened by danwhite-ipc 27
  • [iOS 13] callKit displayed from AppDelegate.m before incoming call listeners

    [iOS 13] callKit displayed from AppDelegate.m before incoming call listeners

    After updating to 3.0.3 and updating my code to meet iOS 13 requirements so CallKit is reported from AppDelegate. But the problem is that when app is closed or in background, the callKit displays very fast before my call class get loaded. So the callKit is shown on screen before listeners are ready and if I accept or reject the call immediately nothing happened. I need to wait for 3 seconds until call listeners are ready then I can accept or reject.

    How can I delay the callKit in AppDelegate until my call class is fully loaded?

    help wanted good first issue 
    opened by ahmadworks 22
  • Possibility of self-managed react-native-callkeep, i.e. with

    Possibility of self-managed react-native-callkeep, i.e. with "setConnectionProperties(PROPERTY_SELF_MANAGED)"?

    UPDATE: This is now a feature request. Can react-native-callkeep be updated so that it can be used with setConnectionProperties(PROPERTY_SELF_MANAGED)?


    Our use case is this: we have a cross-platform video chat app that uses opentok-react-native, and we currently use just push notifications to get users to pair with each other (using react-native-onesignal). When our users tap the push notification, they simply get dropped into our app.

    We would instead want these video chat requests to look like phone calls. This means that we want the phone-call-esque screen to just act as a glorified push notification (tapping the answer button would trigger the exact same behavior that our push notification currently triggers -- opening the app, nothing more and nothing less).

    It seems to me that such a functionality must be possible to do in CallKit and ConnectionService without all the other things that other typical VoIP apps need. For example, requesting the BIND_TELECOM_CONNECTION_SERVICE permission on Android shouldn't be needed, and it would be great to not have to show this to the user. (Or I may be misunderstanding ConnectionService.)

    Is it possible to use react-native-callkeep as something like a full-screen push notification that just happens to look like an incoming phone call?

    enhancement 
    opened by sunweiyang 22
  • ios: support additional options pass from js

    ios: support additional options pass from js

    Support addition options can pass from js method

    updateDisplay

    original:

    updateDisplay = (uuid, displayName, handle)

    new:

    updateDisplay = (uuid, displayName, handle, options = null) where the optional options could be:

    {
      hasVideo: true,
      supportsHolding: true,
      supportsDTMF: true,
      supportsGrouping: true,
      supportsUngrouping: true,
    } 
    

    displayIncomingCall

    original:

    displayIncomingCall = (uuid, handle, localizedCallerName, handleType = 'number', hasVideo = false)

    new:

    displayIncomingCall = (uuid, handle, localizedCallerName, handleType = 'number', hasVideo = false, options = null) where the optional options could be:

    {
      supportsHolding: true,
      supportsDTMF: true,
      supportsGrouping: true,
      supportsUngrouping: true,
    } 
    

    Note for API compatibility:

    Originally, displayIncomingCallalready has hasVideo argument but updateDisplay are not. For api compatibility, I did NOT move displayIncomingCall.hasVideo inside displayIncomingCall.options

    In the earlier time, we've exposed native reportNewIncomingCall and introduced an overloading function for the new payloadargument for api compatibility:

    Earlier Original (as simple api):

    [RNCallKeep reportNewIncomingCall:uuid handle:handle handleType:@"generic" hasVideo:false localizedCallerName:callerName fromPushKit: YES];

    and

    Earlier New (as full api):

    [RNCallKeep reportNewIncomingCall:uuid handle:handle handleType:@"generic" hasVideo:false localizedCallerName:callerName fromPushKit: YES payload:extra];

    We can't have too much overloading functions, so I keep the original one, and extend the new overloading function, so now is:

    This PR Original (as simple api):

    [RNCallKeep reportNewIncomingCall:uuid handle:handle handleType:@"generic" hasVideo:false localizedCallerName:callerName fromPushKit: YES];

    and

    This PR New (as full api):

    [RNCallKeep reportNewIncomingCall:uuid handle:handle handleType:@"generic" hasVideo:false localizedCallerName:callerName supportsHolding: YES supportsDTMF: YES supportsGrouping: YES supportsUngrouping: YES fromPushKit: YES payload: payload];

    TL;DR

    For user using native RNCallKeep reportNewIncomingCall with payload argument should change to [RNCallKeep reportNewIncomingCall:uuid handle:handle handleType:@"generic" hasVideo:false localizedCallerName:callerName supportsHolding: YES supportsDTMF: YES supportsGrouping: YES supportsUngrouping: YES fromPushKit: YES payload: payload];

    opened by zxcpoiu 20
  • help: how to call/listen to ``RNCallKeepBackgroundMessage`` even from ``registerHeadlessTask``

    help: how to call/listen to ``RNCallKeepBackgroundMessage`` even from ``registerHeadlessTask``

    Hi,

    I'm a little confused, I don't understand how to call this headless task, I tried push notifications but nothing was login in any console.

    As I understand it automatically listens to the push notification when the app is killed but my function isn't triggering.

    should I add any specific property in the push notification payload?

    thank you in advance.

    opened by beqramo 19
  • answerCall event not getting called on app killed state iOS

    answerCall event not getting called on app killed state iOS

    Hi,

    My app works fine on iOS when the app is in background or foreground ho ever when app is in killed state then none of the event is getting called I am mainly interested in answerCall Event of RNCallKeep

    opened by shashankmeddo 19
  • Facing the Issue With Reject Call On IOS 13 In Background Mode As App Is Crashing

    Facing the Issue With Reject Call On IOS 13 In Background Mode As App Is Crashing

    Bug report

    When Rejecting the Call On IOS

    • Reproduced on:
    • [ ] iOS 13

    Description

    When I get An Incoming VOIP Notification on IOS devices when App Is in Background mode, App Is Crashed Every time When I Reject the Notification. But Works Fine On Accept Call. And Working Fine On Foreground Mode For Both Accept and reject.

    Steps to Reproduce

    reject an Incoming call when app is in background

    Versions

    - Callkeep:3.0.9
    - React Native: 0.58.6
    - iOS:13.3.1
    - Phone model: All
    

    Logs Xcode Log

    2020-02-13 12:12:19.305827-0500 555 Phone RN[3791:1852152] Apps receving VoIP pushes must post an incoming call (via CallKit or IncomingCallNotifications) in the same run loop as pushRegistry:didReceiveIncomingPushWithPayload:forType:[withCompletionHandler:] without delay. 2020-02-13 12:12:19.307019-0500 555 Phone RN[3791:1852152] *** Assertion failure in -[PKPushRegistry _terminateAppIfThereAreUnhandledVoIPPushes], /BuildRoot/Library/Caches/com.apple.xbs/Sources/PushKit/PushKit-37/PKPushRegistry.m:343 2020-02-13 12:12:19.307351-0500 555 Phone RN[3791:1852152] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Killing app because it never posted an incoming call to the system after receiving a PushKit VoIP push callback.' *** First throw call stack: (0x18463d80c 0x184365fa4 0x18453fc4c 0x1849756f4 0x19831ba5c 0x10241ebd8 0x10242d858 0x19831a9cc 0x10241d7fc 0x10241ebd8 0x10242cc34 0x1845bb3a8 0x1845b639c 0x1845b58a0 0x18e50d328 0x1886a6740 0x100646844 0x184440360) libc++abi.dylib: terminating with uncaught exception of type NSException

    question 
    opened by Chaitanya-Suryadevara 19
  • Is READ_CALL_LOG permission needed when using selfManagedMode?

    Is READ_CALL_LOG permission needed when using selfManagedMode?

    Google play store is rejecting me my app because I haven't requested READ_CALL_LOG permission. Is it required when using selfManagedMode? Calls are not currently registered anymore in the calls log.

    opened by aguedob 18
  • [Android] displayIncomingCall either doesn't called or called with a long delay in when the app is launched from high priority FCM arrives and device in idle mode (Doze)

    [Android] displayIncomingCall either doesn't called or called with a long delay in when the app is launched from high priority FCM arrives and device in idle mode (Doze)

    I'm trying to solve the following problem: receiving an incoming call and displaying an incoming call window in the application, even when the application is killed.

    I assume this is solved as follows:

    1. High priority FCM message is sent to the Android 10 device (Pixel 2).
    2. The App start the HeadlessJS task and call the RNCallKeep.displayIncomingCall function.

    My FCM messages looks like this:

    {
       "data":
    		{
    			"message":"New call",
    			"sound":"default",
    			"title":"New INVITE",
    			"to":"[email protected]",
    			"type":2
    		},
        "priority":"high",
        "registration_ids": ["xxx"],
     } 
    

    Implementation of FCM messages processing and display of an incoming call:

    index.js
    
    ...
    AppRegistry.registerHeadlessTask('RNFirebaseBackgroundMessage', () => bgMessaging);
    ...
    
    bgMessaging.js
    
    ...
    export default async (message: RemoteMessage) => {
       const options = {
            ios: {
                appName: 'MyApp',
                imageName: '../img/TabBar/contacts.imageset/contacts.png',
                ringtoneSound: 'my_ringtone_sound_filename_in_bundle',
                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]
            }
        };
    
        RNCallKeep.setup(options);
        RNCallKeep.setAvailable(true);
       
        if(message.data.type==='2'){
                let _uuid = uuid.v4();
                RNCallKeep.displayIncomingCall(_uuid, "123", "123");
        }
    
        return Promise.resolve();
    }
    

    This works fine and the incoming call screen is displayed:

    1. If the App has just been killed and the device display is still active.
    2. If the App has just been killed and the device’s display has been blocked for a while.

    This doesn't work or works with a long delay (about 60 sec after FCM received I see incoming call display) if the App was killed and the device’s screen was blocked and some time passed, for example 5 minutes. I think device in idle mode (Doze) in this moment .

    What's wrong? How to make guaranteed to open the window of an incoming call after the arrival of a high-priority FCM-message in idle-mode (and inactive-mode) device?

    opened by Prussich 18
  • Call requires permission which may be rejected by user

    Call requires permission which may be rejected by user

    Bug report

    • [x] I've checked the example to reproduce the issue.

    • Reproduced on:

    • [x] Android

    • [ ] iOS

    Description

    Building the project with react-native-callkeep fails on android

    Steps to Reproduce

    Android Manifest.xml

    <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="app.trant"
    	android:exported="true" xmlns:tools="http://schemas.android.com/tools">
    
    	<uses-permission android:name="android.permission.INTERNET" />
    	<uses-permission android:name="android.permission.CAMERA" />
    	<uses-permission android:name="android.permission.MICROPHONE" />
    	<uses-permission android:name="android.permission.RECORD_AUDIO" />
    	<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
    	<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    	<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
    	<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    	<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    	<uses-permission android:name="android.permission.READ_CONTACTS" />
    	<uses-permission android:name="android.permission.WRITE_CONTACTS" />
    	<uses-permission android:name="android.permission.READ_CALL_LOG" />
    	<uses-permission android:name="android.permission.BIND_TELECOM_CONNECTION_SERVICE"
    		tools:ignore="ProtectedPermissions" />
    	<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    	<uses-permission android:name="android.permission.READ_PHONE_STATE" />
    	<uses-permission android:name="android.permission.CALL_PHONE" />
    	<uses-permission android:name="android.permission.READ_CALL_LOG" />
    	<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
    	<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
    	<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
    
    	<uses-feature android:name="android.hardware.camera" />
    	<uses-feature android:name="android.hardware.camera.autofocus" />
    	<uses-feature android:name="android.hardware.audio.output" />
    	<uses-feature android:name="android.hardware.microphone" />
    
    
    	<application android:usesCleartextTraffic="true" android:name=".MainApplication"
    		android:label="@string/app_name" android:icon="@mipmap/ic_launcher"
    		android:allowBackup="false" android:theme="@style/AppTheme">
    		<activity android:exported="true" android:name=".MainActivity"
    			android:label="@string/app_name"
    			android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
    			android:launchMode="singleTask" android:windowSoftInputMode="adjustResize">
    			<intent-filter>
    				<action android:name="android.intent.action.MAIN" />
    				<category android:name="android.intent.category.LAUNCHER" />
    				<action android:name="android.telecom.ConnectionService" />
    
    			</intent-filter>
    		</activity>
    		<service android:exported="true"
    			android:name="io.wazo.callkeep.RNCallKeepBackgroundMessagingService" />
    		<service android:exported="true" android:name="io.wazo.callkeep.VoiceConnectionService"
    			android:label="Wazo"
    			android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE"
    			android:foregroundServiceType="camera|microphone">
    
    			<intent-filter>
    				<action android:name="android.telecom.ConnectionService" />
    			</intent-filter>
    		</service>
    	</application>
    </manifest>
    

    Versions

    - Callkeep: 4.3.3
    - React Native: 0.70.6
    - Android: 12.0.0
    

    Logs

    /node_modules/react-native-callkeep/android/src/main/java/io/wazo/callkeep/RNCallKeepModule.java:367: Error: Call requires permission which may be rejected by user: code should explicitly check to see if permission is available (with checkPermission) or explicitly handle a potential SecurityException [MissingPermission]
            telecomManager.placeCall(uri, extras);
    
    opened by SamuelScheit 0
  • iOS voip push notifications don't work when app is open

    iOS voip push notifications don't work when app is open

    Bug report(Question?)

    • [x] I've checked the example to reproduce the issue.

    • Reproduced on:

    • [ ] Android

    • [x] iOS

    Description

    I've setup callkeep with APNs voip notifictaions and firebase notifications(for non-voip pushes) in an IOS app. When app is killed voip pushes are delived properly, the callkit screen is displayed and when user responds, they are navigated to the proper screen. However when app is active there's no sign of didReceiveIncomingPushWithPayload being called and when app is in the background, it crashes because apparently the completion method for voip pushes isn't being called.

    Usually in the issues it's the other way around, as the killed app isn't being woken up properly, but here when the app is killed everything works fine. I'm not sure what's causing the issues but i guess it might have something to do with the fact that i'm using firebase notifications for other pushes, and that might be causing an issue for voip pushes.

    I'm kinda stuck as to where to go from here and was wondering if someone can provide me with the reason behind this or a way to fix the issue

    Thanks in advance😀

    Steps to Reproduce

    Versions

    - Callkeep: 4.3.3
    - React Native: 0.64.4
    - iOS: 13
    - Android:
    - Phone model: Iphone 7, Iphone 6s
    

    Logs

    When app is in the background, the completion error for voip pushes is shown. when app is in the foreground, there doesn't seem to be any logs/responses, none of the event listerens are called in either situation.

    Sample Code parts

    // AppDelegate.m
    
    
    // IOS push notificaion
    // Required for the register event.
    - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
    {
      [RNCPushNotificationIOS didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
      [RNNotifications didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
    
    }
    // Required for the notification event. You must call the completion handler after handling the remote notification.
    - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
    fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
    {
      NSLog(@"Native notificatoin recieved");
    
      // [RNCPushNotificationIOS didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
      [RNNotifications didReceiveBackgroundNotification:userInfo withCompletionHandler:completionHandler];
    
    }
    // Required for the registrationError event.
    - (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
    {
    //  [RNCPushNotificationIOS didFailToRegisterForRemoteNotificationsWithError:error];
      [RNNotifications didFailToRegisterForRemoteNotificationsWithError:error];
    
    }
    // Required for localNotification event
    - (void)userNotificationCenter:(UNUserNotificationCenter *)center
    didReceiveNotificationResponse:(UNNotificationResponse *)response
             withCompletionHandler:(void (^)(void))completionHandler
    {
      [RNCPushNotificationIOS didReceiveNotificationResponse:response];
    }
    
    
    - (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(PKPushType)type withCompletionHandler:(void (^)(void))completion {
      NSLog(@"pushRegistry:didReceiveIncomingPushWithPayload:forType:withCompletionHandler:%@",
          payload.dictionaryPayload);
    
      NSString *uuid = [payload.dictionaryPayload valueForKey:@"call_uuid"];
       NSString *callerName = [payload.dictionaryPayload valueForKey:@"user"];
       NSString *handle = [payload.dictionaryPayload valueForKey:@"user"];
      
      [RNVoipPushNotificationManager addCompletionHandler:uuid completionHandler:completion];
    
      [RNVoipPushNotificationManager didReceiveIncomingPushWithPayload:payload forType:(NSString *)type];
    
    
      
      [RNCallKeep reportNewIncomingCall: uuid
                                 handle: handle
                             handleType: @"generic"
                               hasVideo: YES
                    localizedCallerName: callerName
                        supportsHolding: YES
                           supportsDTMF: YES
                       supportsGrouping: YES
                     supportsUngrouping: YES
                            fromPushKit: YES
                                payload: payload.dictionaryPayload
                  withCompletionHandler: completion];
    
      completion();
      
    }
    
    
    // App.js
    
    const CallKeepSetup = () => {
      const logger = useLogger('CallKeep');
      const navigation = useNavigation();
      const dispatch = useDispatch();
    
      const answerCall = ({ callUUID }) => {
        logger.info("Call recieved, answering call...")
        AsyncStorage.setItem('currentCallUUID', callUUID);
        try {
          logger.info("Starting Callkeep call")
          RNCallKeep.startCall(callUUID, 'Police', "Police", 'generic', true);
          logger.info("Call started successfully")
        } catch(e) {
          logger.error("Failed to start callkeep call")
        }
    
        setTimeout(() => {
          logger.info("Setting current active call...")
          try {
            RNCallKeep.setCurrentCallActive(callUUID);
            logger.info("Current active call set");
          } catch(e) {
            logger.error("Failed to set current call", {error: e});
    
          }
        }, 1000);
        logger.info("Call started successfully, setting active call")
    
    
        // On Android display the app when answering a video call
        if (!isIOS) {
          console.log('bringing app to foreground');
          RNCallKeep.backToForeground();
        }
    
        logger.info("Setting current call UUID")
        dispatch(setCurrentCallUUID(callUUID))
    
        logger.info("Navigating to call screen")
    
          navigation.navigate('Video Call');
    
      };
    
      const endCall = ({ callUUID }) => {
        logger.info("Ending call")
        
        try {
          dispatch(endCallWithUUID(callUUID));
          RNCallKeep.endAllCalls();
          logger.info("Call ended")
    
        } catch(e) {
          logger.error("Failed to end call", { error: e})
        }
      };
    
      const didDisplayIncomingCall = async ({ callUUID, payload, handle, }) => {
        try {
          logger.info('Recieved call with data', { payload, callUUID, handle });
          dispatch(
                   startVideoChatWithouActivating({
              token: payload.token,
              room_name: payload.room_name,
              call_id: payload.call_id,
              friend: payload.friend,
              callUUID,
              call_uuid: callUUID,
              // location: JSON.parse(data.location ?? '{}'),
            })
          );
          logger.info('Call displayed with data', { payload, callUUID, handle });
        } catch(e) {
          logger.error('Failed to save call data', { payload, callUUID, handle });
        }
      }
    
      const handlePreJSEvents = (events) => {
        logger.info('PreJS events', { events });
        for (let event of events) {
          if (event.name == "RNCallKeepDidDisplayIncomingCall") {
            logger.info('PreJS events: didDisplayIncomingCall', { event });
            didDisplayIncomingCall(event.data)
          } else if (event.name == 'RNCallKeepAnswerCall') {
            logger.info('PreJS events: answerCall', { event });
            answerCall(event.data)
          } else if (event.name == 'RNCallKeepEndCall') {
            logger.info('PreJS events: endCall', { event });
            endCall(event.data)
          }
        }
      }
    
      const initializeCallKeep = () => {
        try {
          logger.info('Call keep initiated successfully');
          RNCallKeep.setAvailable(true);
    
          RNCallKeep.addEventListener('answerCall', answerCall);
          RNCallKeep.addEventListener('didReceiveStartCallAction', answerCall);
          RNCallKeep.addEventListener('endCall', endCall);
          RNCallKeep.addEventListener('didDisplayIncomingCall', didDisplayIncomingCall);
          
          if (isIOS) {
            RNCallKeep.addEventListener('didLoadWithEvents', handlePreJSEvents);
          }
        } catch (err) {
          logger.error('Failed to initialize call keep', {
            error: err,
            msg: err.message,
          });
          console.error('initializeCallKeep error:', err.message);
        }
      };
    
    
      useEffect(() => {
        initializeCallKeep();
        loadInitialCall();
    
        return () => {
          RNCallKeep.removeEventListener('answerCall', answerCall);
          RNCallKeep.removeEventListener('didReceiveStartCallAction', answerCall);
          RNCallKeep.removeEventListener('endCall', endCall);
          RNCallKeep.removeEventListener('didDisplayIncomingCall', didDisplayIncomingCall);
          if (isIOS) {
            RNCallKeep.removeEventListener('didLoadWithEvents', handlePreJSEvents);
          }
        };
      }, []);
    
      return <></>;
    };
    
    
    
    opened by atrin-hojjat 0
  • Map already consumed exception (VoiceBroadcastReceiver.onReceive)

    Map already consumed exception (VoiceBroadcastReceiver.onReceive)

    Hello everyone) After updating to the latest version of the program, there were a lot of crash reports with the following error:

    Exception com.facebook.react.bridge.ObjectAlreadyConsumedException: Map already consumed
      at com.facebook.react.bridge.WritableNativeMap.putString
      at io.wazo.callkeep.RNCallKeepModule$VoiceBroadcastReceiver.onReceive (RNCallKeepModule.java:1158)
      at androidx.localbroadcastmanager.content.LocalBroadcastManager.executePendingBroadcasts (LocalBroadcastManager.java:313)
      at androidx.localbroadcastmanager.content.LocalBroadcastManager$1.handleMessage (LocalBroadcastManager.java:121)
      at android.os.Handler.dispatchMessage (Handler.java:106)
      at android.os.Looper.loopOnce (Looper.java:233)
      at android.os.Looper.loop (Looper.java:344)
      at android.app.ActivityThread.main (ActivityThread.java:8191)
      at java.lang.reflect.Method.invoke
      at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:584)
      at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1034)
    

    Maybe someone also faced this problem?

    • Reproduced on:
    • [X] Android
    • [ ] iOS

    Versions

    - Callkeep: ^4.3.3
    - React Native: 0.63.5
    - iOS: -
    

    Here are some screenshots from google play console:
    image_2022_12_14T13_40_05_482Z image_2022_12_14T13_40_36_648Z

    opened by KolissnikBogdan 3
  • react native fullScreen notification incoming call need to support both ios and Android

    react native fullScreen notification incoming call need to support both ios and Android

    Bug report

    Any suggestion for Incoming call notification full screen while lock screen state and notification popup awake the device. please help on this need to work both platforms. latest version of react native unable to support this feature. Please help on this. thanks in advance. download-1 download

    • Reproduced on:
    • [ ] Android
    • [ ] iOS

    Description

    Steps to Reproduce

    Versions

    - Callkeep:
    - React Native:
    - iOS:
    - Android:
    - Phone model: 
    

    Logs

    Paste here
    
    opened by chganesh 2
  • backToForeground not working on Galaxy Z Flip and Z Fold series.

    backToForeground not working on Galaxy Z Flip and Z Fold series.

    Bug report

    • [ v ] I've checked the example to reproduce the issue.

    • Reproduced on:

    • [ v ] Android

    • [ ] iOS

    Description

    My app doesn't come up to foreground when I get a call with or without self-managed mode on foldable Galaxy models. In case of using self-managed mode, phone does just vibrate or ring but app is not opened in both of background state and completely closed state. Without self-managed mode, system call UI is shown, and when I answer the call, system call UI is still shown and app is not opened. These are happened only on Galaxy Z Flip and Fold series. I think backToForeground API is not working on these models.

    Steps to Reproduce

    Call Galaxy Z Flip or Fold user.

    Versions

    - Callkeep:4.3.3
    - React Native:0.66.3
    - iOS:
    - Android:12
    - Phone model: Galaxy Z Flip 3, Galaxy Z Flip 4, Galaxy Z Fold 4, ...
    

    Logs

    Paste here
    
    opened by taekeunn 1
  • Bump qs from 6.7.0 to 6.11.0 in /example

    Bump qs from 6.7.0 to 6.11.0 in /example

    Bumps qs from 6.7.0 to 6.11.0.

    Changelog

    Sourced from qs's changelog.

    6.11.0

    • [New] [Fix] stringify: revert 0e903c0; add commaRoundTrip option (#442)
    • [readme] fix version badge

    6.10.5

    • [Fix] stringify: with arrayFormat: comma, properly include an explicit [] on a single-item array (#434)

    6.10.4

    • [Fix] stringify: with arrayFormat: comma, include an explicit [] on a single-item array (#441)
    • [meta] use npmignore to autogenerate an npmignore file
    • [Dev Deps] update eslint, @ljharb/eslint-config, aud, has-symbol, object-inspect, tape

    6.10.3

    • [Fix] parse: ignore __proto__ keys (#428)
    • [Robustness] stringify: avoid relying on a global undefined (#427)
    • [actions] reuse common workflows
    • [Dev Deps] update eslint, @ljharb/eslint-config, object-inspect, tape

    6.10.2

    • [Fix] stringify: actually fix cyclic references (#426)
    • [Fix] stringify: avoid encoding arrayformat comma when encodeValuesOnly = true (#424)
    • [readme] remove travis badge; add github actions/codecov badges; update URLs
    • [Docs] add note and links for coercing primitive values (#408)
    • [actions] update codecov uploader
    • [actions] update workflows
    • [Tests] clean up stringify tests slightly
    • [Dev Deps] update eslint, @ljharb/eslint-config, aud, object-inspect, safe-publish-latest, tape

    6.10.1

    • [Fix] stringify: avoid exception on repeated object values (#402)

    6.10.0

    • [New] stringify: throw on cycles, instead of an infinite loop (#395, #394, #393)
    • [New] parse: add allowSparse option for collapsing arrays with missing indices (#312)
    • [meta] fix README.md (#399)
    • [meta] only run npm run dist in publish, not install
    • [Dev Deps] update eslint, @ljharb/eslint-config, aud, has-symbols, tape
    • [Tests] fix tests on node v0.6
    • [Tests] use ljharb/actions/node/install instead of ljharb/actions/node/run
    • [Tests] Revert "[meta] ignore eclint transitive audit warning"

    6.9.7

    • [Fix] parse: ignore __proto__ keys (#428)
    • [Fix] stringify: avoid encoding arrayformat comma when encodeValuesOnly = true (#424)
    • [Robustness] stringify: avoid relying on a global undefined (#427)
    • [readme] remove travis badge; add github actions/codecov badges; update URLs
    • [Docs] add note and links for coercing primitive values (#408)
    • [Tests] clean up stringify tests slightly
    • [meta] fix README.md (#399)
    • Revert "[meta] ignore eclint transitive audit warning"

    ... (truncated)

    Commits
    • 56763c1 v6.11.0
    • ddd3e29 [readme] fix version badge
    • c313472 [New] [Fix] stringify: revert 0e903c0; add commaRoundTrip option
    • 95bc018 v6.10.5
    • 0e903c0 [Fix] stringify: with arrayFormat: comma, properly include an explicit `[...
    • ba9703c v6.10.4
    • 4e44019 [Fix] stringify: with arrayFormat: comma, include an explicit [] on a s...
    • 113b990 [Dev Deps] update object-inspect
    • c77f38f [Dev Deps] update eslint, @ljharb/eslint-config, aud, has-symbol, tape
    • 2cf45b2 [meta] use npmignore to autogenerate an npmignore file
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 0
Releases(4.3.3)
  • 4.3.2(Feb 16, 2022)

    • Store Android settings #499
    • Implemented onCreateIncomingConnectionFailed #500
    • Fix ConcurrentModificationException #502
    • fix native event emitter warnings #505
    • Trigger audio route changes #514
    • Fix crash on onAudioRouteChange when output is nil #516
    • Feat/add incoming call error code (iOS) #519
    • Consistent data structure, in delayedEvents. #521
    • Added RNCallKeepDidChangeAudioRoute to supportedEvents #523
    • Add setConnectionState method for Android #524
    Source code(tar.gz)
    Source code(zip)
  • 4.3.0(Oct 13, 2021)

    • Fix: abnormal behavior of speaker button on iOS #495
    • Added missing semicolons #485
    • Improve documentation #473
    • Fix registerPhoneAccount method when manually registering Android phone #472
    • chore: fix compilation issue on improper function #468
    • Update the README #464
    • check if a key exists in map #463
    • Switch audio devices #462
    • Allow to display incoming call natively on Android #440
    • Remove READ_CALL_LOG permission on Android and add documentation about it #438
    • Implement Android Connection.onSilence() event #431
    • Documentation for getInitialEvents added #421
    • Handle all onAnswer/onReject Connection events #420
    • Add getInitialEvents helper method #417
    • Remove colon in Android log TAG and add more logs #409
    Source code(tar.gz)
    Source code(zip)
  • 4.2.0(May 17, 2021)

    • Android self managed documentation #407
    • Document the use of foregroundServiceType in Android < 11 #405
    • Adding mavenCentral() as jcenter() is shutting #400
    • Implemented self managed mode support for Android #395
    • Support IOS setup in AppDelegate.m #394
    • Export emit to ease didLoadWithEvents handling #387
    • Add missing foregroundService to Android options #384
    Source code(tar.gz)
    Source code(zip)
  • 4.1.0(Mar 22, 2021)

    • Audio route to speaker for Android platform #295
    • [iOS] Add support for answering incoming call #300
    • doc: add note for didLoadWithEvents in readme #333
    • Bump ini from 1.3.5 to 1.3.7 in /example #335
    • Include calls in recent types #356
    • Fix return type on setup #362
    • fix: avoid isCallActive returning undefined #364
    • feat: add getCalls method for ios only #366
    • docs: update readme for react-native-voip-push-notification new link #370
    • androidx import #371
    • Fixing types #373
    • Avoid to check for reachability everytime we make a call #376
    Source code(tar.gz)
    Source code(zip)
  • 4.0.1(Dec 1, 2020)

    • Make foreground service compatible with SDK version < 30 #331
    • [Android] fix app crash after permissions dialog closed #324
    • fix: not to add didLoadWithEvents in constructor #315
    Source code(tar.gz)
    Source code(zip)
  • 4.0.0(Nov 24, 2020)

  • 3.1.4(Nov 11, 2020)

  • 3.1.3(Nov 11, 2020)

  • 3.1.2(Nov 11, 2020)

    • Fix react native firebase documentation url #309
    • Fix potential NullPointerException in hasPermissions #306
    • Add new methods to improve calls and phone account #298
    • Fix typo in readme #247
    • Update index.d.ts #272
    Source code(tar.gz)
    Source code(zip)
  • 3.1.1(Jul 21, 2020)

    • [Android] Split setup into registerPhoneAccount and registerAndroidEvents #242
    • Handle issue with JS not initialized on start to fix #107 #205
    Source code(tar.gz)
    Source code(zip)
  • 3.1.0(Jul 6, 2020)

    This new 3.1.0 may break app using Flutter instead of react-native. As this library is designed to work for react-native, we have to rethink the way we should wake up the application on Android that also works with Flutter

    • Android: Revert wakeUpApplication to use react-native class #234
    Source code(tar.gz)
    Source code(zip)
  • 3.0.15(Jun 23, 2020)

  • 3.0.14(Jun 23, 2020)

  • 3.0.13(Jun 23, 2020)

    • New Method Check if Active Call with UUID #172
    • Add completionHandler for reportNewIncomingCall method #191
    • Fix NSInvalidArgumentException when localizedCallerName is empty #166
    • document removeEventListener #165
    • Fix Video button not working in iOS Lock Screen #171
    • ios: fix reportNewIncomingCall should use fromPushKit #174
    Source code(tar.gz)
    Source code(zip)
  • 3.0.12(Jun 23, 2020)

  • 3.0.11(Jun 23, 2020)

    • readme/doc: fix typo and remove duplicated endAllCalls method sections #168
    • Recreate Mark Corner's PR #167
    • Exposed the method reportEndCallWithUUID to handle a cancel VoIP Push Notification to tears down an incoming call #164
    • Pass data from VoIP Notification down to RN #149
    Source code(tar.gz)
    Source code(zip)
  • 3.0.10(Jun 23, 2020)

  • v3.0.9(Jun 23, 2020)

    • Fix docs for didDisplayIncomingCall #145
    • Fixed typing issue #147
    • Add a troubleshooting note on using a valid uuid #144
    • Add a check for INStartCallIntent.callCapability not available on iOS 13.2 #134
    Source code(tar.gz)
    Source code(zip)
  • v3.0.8(Jun 23, 2020)

  • v3.0.7(Jun 23, 2020)

  • v3.0.6(Jun 23, 2020)

  • v3.0.5(Jun 23, 2020)

  • v3.0.0(Aug 25, 2019)

  • 2.0.1(Mar 19, 2019)

  • v2.0.0(Feb 5, 2019)

Owner
React Native WebRTC
A home for all things around React Native and WebRTC
React Native WebRTC
Alarm clock functionality for react native ios and android using react-native-push-notification and react-native-community/async-storage

react-native-simple-alarm Alarm clock functionality for react native ios and android built using react-native-push-notification and react-native-commu

Jordan Daniels 74 Jan 6, 2023
Your best friend when working with the latest and greatest Contacts Framework in iOS 9+ in React Native.

Your best friend when working with the latest and greatest Contacts Framework in iOS 9+ and combining that with Android 6 (SDK 23)+ support Platform C

Joshua Pinter 155 Dec 6, 2022
A library for React-Native to help you download large files on iOS and Android both in the foreground and most importantly in the background.

react-native-background-downloader A library for React-Native to help you download large files on iOS and Android both in the foreground and most impo

Eko Labs 271 Dec 27, 2022
React Native ssl pinning and cookies handling based on okhttp3 on (Android). and AFNetworking on (iOS)

react-native-ssl-pinning React-Native ssl pinning & public key pinning using OkHttp 3 in Android, and AFNetworking on iOS. NOTES: for RN 0.60.0 or lat

Maxim Toyberman 260 Dec 19, 2022
Device Information for React Native iOS and Android

react-native-device-info Device Information for React Native. TOC Installation Linking Usage API Troubleshooting Release Notes react-native-dom / reac

null 6k Dec 31, 2022
An unified permissions API for React Native on iOS and Android

☝?? react-native-permissions A unified permissions API for React Native on iOS, Android and Windows. (For Windows only builds 18362 and later are supp

Mathieu Acthernoene 3.4k Jan 8, 2023
React native package to add in app review functionality for android and ios applications

react-native-in-app-review Now you can integrate this to react native and in-app review dialog can be shown to user. User doesn't need to move to play

Ravi Rupareliya 74 Nov 2, 2022
A cordova battery status listener for react-native, support for ios and android

React Native BatteryStatus (remobile) A cordova battery status listener for react-native, support for ios and android Installation npm install @remobi

YunJiang.Fang 14 Jan 28, 2020
Event Source implementation for React Native. Server-Sent Events (SSE) for iOS and Android 🚀

React Native EventSource (Server-Sent Events) ?? Your missing EventSource implementation for React Native! React-Native-SSE library supports TypeScrip

Binaryminds 52 Dec 16, 2022
React native geolocation service for iOS and android

React native geolocation service for iOS and android

Iftekhar Rifat 1.4k Jan 6, 2023
React Native library for PSPDFKit for iOS, Android and Windows UWP.

React Native Library for PSPDFKit for iOS, Android & Windows UWP. (PDF SDK for React Native) This library requires a valid license of PSPDFKit. Licens

PSPDFKit GmbH 120 Dec 14, 2022
Fully customizable, easy to use checkbox with flexible component by React Native on Android and iOS

Installation Add the dependency: npm i react-native-checkbox-flex Peer Dependencies IMPORTANT! You need install them "@freakycoder/react-native-bounce

FreakyCoder 11 Nov 20, 2021
🔥 A well-tested feature-rich modular Firebase implementation for React Native. Supports both iOS & Android platforms for all Firebase services.

React Native Firebase React Native Firebase is a collection of official React Native modules connecting you to Firebase services; each module is a lig

Invertase 10.5k Jan 1, 2023
React-Native Haptic Feedback for iOS with Android similar behaviour.

react-native-haptic-feedback Contributions welcome Right now the Android implementation is a small Vibrate pattern, similar to the "feeling" of the iO

Junina 645 Jan 6, 2023
Secure Storage for React Native (Android & iOS)

RNSecureStorage Secure Storage for React Native (Android & iOS) - Keychain & Keystore v3.0.0-beta.0 This version still under development. But you can

Talut TASGIRAN 160 Dec 29, 2022
React Native boilerplate supporting multiple platforms: Android, iOS, macOS, Windows, web, browser extensions, Electron.

React Native Universal Monorepo ( ?? WIP) A React Native monorepo boilerplate supporting multiple platforms: Android, iOS, macOS, Windows, web, browse

Matteo Mazzarolo 1.5k Dec 31, 2022
A wrapper of Lock to use with React Native (iOS & Android)

A wrapper of Lock to use with React Native (iOS & Android)

Auth0 277 Nov 11, 2022
This is a e-commerce app build over react native runs over android & ios.

CliqApp This is a Ecommerce app build over react native runs over android & ios. PLEASE HELP ME TO CONTRIBUTE MORE PROJECT LIKE THIS! Watch the video

Rizvan Hawaldar 76 Jan 3, 2023
Use the built-in share view from iOS and Android to let the user share on Facebook and Twitter.

Use the built-in share view from iOS and Android to let the user share on Facebook and Twitter. It will use the user's existing account without having to get new authorizations. You can even preset text, image and link for the share view.

Kim Døfler 415 Oct 9, 2022