react-native-voip-push-notification

repository·master·Indexed 42 days ago

https://github.com/react-native-webrtc/react-native-voip-push-notification

A React Native bridge for Apple's PushKit framework that enables VoIP push notifications on iOS. Version 3.3.3 provides a JavaScript API to register for VoIP tokens and handle incoming notifications, designed to work in tandem with CallKit to manage incoming call notifications.

Tokens
3.8K
Snippets
9
Records
12
Agent score
4%

What's inside react-native-voip-push-notification

  1. Handle missed events with didLoadWithEvents

    master

    Since VoIP pushes are time-sensitive, they may arrive while the React Native JavaScript bridge is still initializing. The didLoadWithEvents event provides a way to catch these missed events.

    When this event fires, it returns an array of event objects. Each object contains a name and data. You should check the name against the following constants to process them correctly:

    • VoipPushNotification.RNVoipPushRemoteNotificationsRegisteredEvent
    • VoipPushNotification.RNVoipPushRemoteNotificationReceivedEvent
    VoipPushNotification.addEventListener('didLoadWithEvents', (events) => {
        if (!events || !Array.isArray(events) || events.length < 1) {
            return;
        }
        for (let voipPushEvent of events) {
            let { name, data } = voipPushEvent;
            if (name === VoipPushNotification.RNVoipPushRemoteNotificationsRegisteredEvent) {
                // Manually trigger your registration logic with 'data'
            } else if (name === VoipPushNotification.RNVoipPushRemoteNotificationReceivedEvent) {
                // Manually trigger your notification logic with 'data'
            }
        }
    });
  2. Use the JavaScript API for VoIP Push Notifications

    master

    The JavaScript API allows you to register for VoIP tokens and handle incoming notifications. Because VoIP pushes are time-sensitive, you should set up your event listeners as early as possible in your application lifecycle (e.g., in componentDidMount of your root component or at a global scope).

    Key Methods

    • registerVoipToken(): Registers the PushKit delegate. If you have already registered on the native side, this acts as a no-op but will fire the register event if a cached token is available.
    • onVoipNotificationCompleted(notification.uuid): Notifies PushKit that the received VoIP push has been handled. This is crucial for managing the system's push lifecycle.

    Event Listeners

    • 'register': Fired when PushKit provides the latest token. Use this to send the token to your APNs provider server.
    • 'notification': Fired when a VoIP push notification is received. Use this to initiate calls or show local notifications.
    • 'didLoadWithEvents': Fired when events (like register or notification) occurred before the JavaScript bridge was fully initialized. This allows you to process missed events manually.
    import VoipPushNotification from 'react-native-voip-push-notification';
    
    // 1. Subscribe to 'register' to get the token
    VoipPushNotification.addEventListener('register', (token) => {
        // Send token to your server
    });
    
    // 2. Subscribe to 'notification' to handle incoming calls
    VoipPushNotification.addEventListener('notification', (notification) => {
        // Handle the call (e.g., show UI, register VoIP client)
        
        // Tell PushKit the notification is handled
        VoipPushNotification.onVoipNotificationCompleted(notification.uuid);
    });
    
    // 3. Handle events that happened before JS bridge was ready
    VoipPushNotification.addEventListener('didLoadWithEvents', (events) => {
        if (!events || !Array.isArray(events)) return;
        
        for (let event of events) {
            if (event.name === VoipPushNotification.RNVoipPushRemoteNotificationsRegisteredEvent) {
                // Handle registration
            } else if (event.name === VoipPushNotification.RNVoipPushRemoteNotificationReceivedEvent) {
                // Handle notification
            }
        }
    });
    
    // 4. Trigger registration
    VoipPushNotification.registerVoipToken();
  3. Manually link react-native-voip-push-notification in Xcode

    master

    If auto-linking is not working (for older RN versions), follow these steps:

    1. Add PushKit Framework: In Xcode, select Build Phases -> Link Binary With Libraries and add PushKit.framework.
    2. Add the Library:
      • Option 1 (rnpm): Run rnpm link react-native-voip-push-notification. Ensure Header Search Paths is set to recursive.
      • Option 2 (Manual):
        • Drag node_modules/react-native-voip-push-notification/ios/RNVoipPushNotification.xcodeproj into your project's Libraries folder.
        • In Build Phases -> Link Binary With Libraries, add libRNVoipPushNotification.a from the project you just dragged in.
        • In Build Settings -> Header Search Paths, add $(SRCROOT)/../node_modules/react-native-voip-push-notification/ios/RNVoipPushNotification and set it to recursive.
  4. Install react-native-voip-push-notification

    master

    Install the package via npm and then install the iOS dependencies using CocoaPods.

    Requirements:

    • iOS version must be >= 8.0.
    • React Native version: 1.1.0+ (RN 40+) or 2.0.0+ (RN 60+).

    Xcode Configuration: In Xcode -> Signing & Capabilities, you must enable:

    • Background Modes -> Voice over IP
    • +Capability -> Push Notifications
    npm install --save react-native-voip-push-notification
    # --- if using pod
    cd ios/ && pod install
  5. Configure AppDelegate.m for VoIP Push

    master

    To handle VoIP pushes, you must modify your AppDelegate.m to import the necessary headers and implement the PushKit delegate methods.

    Important: It is highly recommended to call [RNVoipPushNotificationManager voipRegistration] inside didFinishLaunchingWithOptions as early as possible to avoid delays caused by JS initialization.

    Critical Requirement: On iOS 13+, you must report incoming VoIP pushes to CallKit immediately upon receipt. Failure to do so will result in the system terminating your app. It is recommended to use react-native-callkeep alongside this module.

    #import <PushKit/PushKit.h>
    #import "RNVoipPushNotificationManager.h"
    
    // ... inside didFinishLaunchingWithOptions
    [RNVoipPushNotificationManager voipRegistration];
    
    // ... implement PushKit delegate methods
    - (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(PKPushType)type {
      [RNVoipPushNotificationManager didUpdatePushCredentials:credentials forType:(NSString *)type];
    }
    
    - (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(PKPushType)type withCompletionHandler:(void (^)(void))completion {
      // 1. Extract payload data
      NSString *uuid = payload.dictionaryPayload[@"uuid"];
      // ...
    
      // 2. Process the push
      [RNVoipPushNotificationManager didReceiveIncomingPushWithPayload:payload forType:(NSString *)type];
    
      // 3. MANDATORY: Report to CallKit ASAP
      // [RNCallKeep reportNewIncomingCall:...]
    
      completion();
    }
  6. Configure APNs for VoIP Push

    master

    When sending VoIP push notifications from your server to APNs, ensure the following settings are applied for iOS 13+ compatibility:

    • apns-push-type must be set to 'voip'.
    • apns-expiration should be adjusted according to your specific call logic.

    Note on Silent/Background Pushes: VoIP pushes are intended strictly for incoming call notifications. If you need to perform background updates or cancel calls, use a Notification Service Extension or Background Push instead. For Background Push, ensure:

    1. Xcode -> Signing & Capabilities -> Background Modes -> Remote Notifications is enabled.
    2. The APNs payload sets:
      • content-available = 1
      • apns-push-type = 'background'
      • apns-priority = 5
  7. Reference the Native API for AppDelegate.m

    master

    The following native methods are available for use within AppDelegate.m. These are primarily used to handle VoIP pushes immediately, often before the JavaScript bridge is available, which is critical for time-sensitive VoIP tasks.

    MethodDescription
    (void)voipRegistrationRegister the delegate for PushKit immediately in AppDelegate.m
    (void)didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(NSString *)typeFires the 'register' event to the JS side
    (void)didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(NSString *)typeFires the 'notification' event to the JS side
    (void)addCompletionHandler:(NSString *)uuid completionHandler:(RNVoipPushNotificationCompletion)completionHandlerAdds a completion handler to the RNVoipPush module
    (void)removeCompletionHandler:(NSString *)uuidRemoves a completion handler from the RNVoipPush module
  8. Handle VoIP push notification events with addEventListener()

    master

    Use addEventListener(type, handler) to listen for specific VoIP lifecycle events. The library supports one listener per event type at a time; calling addEventListener for an existing type will automatically remove the previous listener to prevent memory leaks.

    Supported event types:

    • notification: Fired when a remote notification is received. The handler receives the notificationPayload.
    • register: Fired when the user registers for remote notifications. The handler receives the deviceToken.
    • didLoadWithEvents: Fired when the user has initially subscribed to a listener and the system has cached events that occurred while the app was not running. The handler receives the events array.
    import RNVoipPushNotification from 'react-native-voip-push-notification';
    
    // Listen for incoming notifications
    RNVoipPushNotification.addEventListener('notification', (notificationPayload) => {
      console.log('Received notification:', notificationPayload);
    });
    
    // Listen for device token registration
    RNVoipPushNotification.addEventListener('register', (deviceToken) => {
      console.log('VoIP Device Token:', deviceToken);
    });
    
    // Listen for cached events
    RNVoipPushNotification.addEventListener('didLoadWithEvents', (events) => {
      console.log('Cached events:', events);
    });
  9. Complete VoIP notification processing with onVoipNotificationCompleted()

    master

    For iOS 11+, Apple requires you to signal when you have finished processing a VoIP push notification. Call onVoipNotificationCompleted(uuid) to execute the completion handler.

    Requirement: You must ensure that your AppDelegate.m calls [RNVoipPushNotificationManager addCompletionHandler:uuid completionHandler:completion]; inside the didReceiveIncomingPushWithPayload method to enable this functionality.

    import RNVoipPushNotification from 'react-native-voip-push-notification';
    
    // After processing the notification payload
    RNVoipPushNotification.onVoipNotificationCompleted(uuid);
  10. Remove event listeners with removeEventListener()

    master

    To prevent memory leaks, call removeEventListener(type) when the listener is no longer needed, typically in a component's componentWillUnmount or a useEffect cleanup function.

    Supported types:

    • 'notification'
    • 'register'
    • 'didLoadWithEvents'
    import RNVoipPushNotification from 'react-native-voip-push-notification';
    
    // Remove a specific listener
    RNVoipPushNotification.removeEventListener('notification');
  11. Reference: RNVoipPushNotification event constants

    master

    The RNVoipPushNotification class provides static getters to access the underlying native event names. These are useful if you are working with low-level event emitters, though addEventListener is the preferred high-level API.

    // Event Name Constants
    RNVoipPushNotification.RNVoipPushRemoteNotificationsRegisteredEvent; // 'register'
    RNVoipPushNotification.RNVoipPushRemoteNotificationReceivedEvent;    // 'notification'
    RNVoipPushNotification.RNVoipPushDidLoadWithEvents;                // 'didLoadWithEvents'