react-native-voip-push-notification icon indicating copy to clipboard operation
react-native-voip-push-notification copied to clipboard

VoipPushNotification.addEventListener('notification', () => {}); call twice

Open w4ugit opened this issue 2 years ago • 13 comments

I have the following code in app.js

useEffect(() => {
    if (Platform.OS === 'ios') {
      VoipPushNotification.addEventListener('register', token => {
        store.dispatch(setApnsToken(token));
      });

      VoipPushNotification.addEventListener('notification', notification => {
        Alert.alert('Call answer');
        const incomingCallAnswer = () => {
          store.dispatch(
            setCall({
              label: notification.aps.number,
              number: notification.aps.number,
              type: notification.aps.type,
              uuid: notification.aps.uuid,
              status: 'incoming',
            }),
          );
        };

        const endIncomingCall = () => {
          Incomingvideocall.endAllCall();
        };
        Incomingvideocall.configure(incomingCallAnswer, endIncomingCall);
        VoipPushNotification.onVoipNotificationCompleted(notification.uuid);
        return;
      });

      VoipPushNotification.registerVoipToken(); // --- register token
    }
  }, []);

when push comes i get two calls Alert.alert('Call answer');

What could be the problem?

w4ugit avatar Jan 11 '24 11:01 w4ugit

The problem could be in your component re-render. Just track if it was re-rendered or it was fired twice. I bet it is re-render ) even without seeing other parts of your app.

Romick2005 avatar Jan 11 '24 11:01 Romick2005

To make sure it wasn't, I removed everything else and left only this code

import React, {useEffect} from 'react';
import i18n from 'i18next';
import {initReactI18next} from 'react-i18next';
import uk from './src/i18n/uk';
import en from './src/i18n/en';
import de from './src/i18n/de';
import es from './src/i18n/es';
import {Alert, NativeModules, Platform, Text} from 'react-native';
import VoipPushNotification from 'react-native-voip-push-notification';

const locale =
  Platform.OS === 'ios'
    ? NativeModules.SettingsManager.settings.AppleLocale
    : NativeModules.I18nManager.localeIdentifier;

i18n.use(initReactI18next).init({
  compatibilityJSON: 'v3',
  resources: {
    en: en,
    uk: uk,
    de: de,
    es: es,
  },
  lng: 'en',
  interpolation: {
    escapeValue: false,
  },
});

const App = ({bgState}) => {
  useEffect(() => {
    if (Platform.OS === 'ios') {
      VoipPushNotification.addEventListener('register', token => {});

      VoipPushNotification.addEventListener('notification', notification => {
        Alert.alert('Call answer');
        VoipPushNotification.onVoipNotificationCompleted(notification.uuid);
      });

      VoipPushNotification.addEventListener('didLoadWithEvents', events => {
        if (!events || !Array.isArray(events) || events.length < 1) {
          return;
        }
      });

      VoipPushNotification.registerVoipToken(); // --- register token
    }
  }, []);

  return <Text>App</Text>;
};

export default App;

the problem has not gone away

w4ugit avatar Jan 11 '24 12:01 w4ugit

Here is my AppDelegate.mm file

#import "AppDelegate.h"
#import <Firebase.h>
#import "RNBootSplash.h"
#import "RNCallKeep.h"
#import <React/RCTBundleURLProvider.h>
#import "Orientation.h"
#import <PushKit/PushKit.h>
#import "RNVoipPushNotificationManager.h"
#import "RNFBMessagingModule.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{

  self.moduleName = @"Calls";
  // You can add your custom initial props in the dictionary below.
  // They will be passed down to the ViewController used by React Native.
  self.initialProps = @{};
  self.initialProps = [RNFBMessagingModule addCustomPropsToUserProps:nil withLaunchOptions:launchOptions];
  [FIRApp configure];
  [super application:application didFinishLaunchingWithOptions:launchOptions];
  [RNBootSplash initWithStoryboard:@"BootSplash" rootView:self.window.rootViewController.view];
  [RNVoipPushNotificationManager voipRegistration];

  return YES;
}

- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG
  return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
#else
  return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif
}

/// This method controls whether the `concurrentRoot`feature of React18 is turned on or off.
///
/// @see: https://reactjs.org/blog/2022/03/29/react-v18.html
/// @note: This requires to be rendering on Fabric (i.e. on the New Architecture).
/// @return: `true` if the `concurrentRoot` feature is enabled. Otherwise, it returns `false`.
- (BOOL)concurrentRootEnabled
{
  return true;
}

- (BOOL)application:(UIApplication *)application
continueUserActivity:(NSUserActivity *)userActivity
  restorationHandler:(void(^)(NSArray<id<UIUserActivityRestoring>> * __nullable restorableObjects))restorationHandler
{
  return [RNCallKeep application:application
           continueUserActivity:userActivity
             restorationHandler:restorationHandler];
}

- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
  return [Orientation getOrientation];
}

- (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(PKPushType)type {
  // Register VoIP push token (a property of PKPushCredentials) with server
  [RNVoipPushNotificationManager didUpdatePushCredentials:credentials forType:(NSString *)type];
}

- (void)pushRegistry:(PKPushRegistry *)registry didInvalidatePushTokenForType:(PKPushType)type
{
  // --- The system calls this method when a previously provided push token is no longer valid for use. No action is necessary on your part to reregister the push type. Instead, use this method to notify your server not to send push notifications using the matching push token.
}

- (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(PKPushType)type withCompletionHandler:(void (^)(void))completion {
  // --- NOTE: apple forced us to invoke callkit ASAP when we receive voip push
  // --- see: react-native-callkeep

  // --- Retrieve information from your voip push payload
//   NSString *uuid = payload.dictionaryPayload[@"aps"][@"uuid"];
//   NSString *callerName = [NSString stringWithFormat:@"%@ Calling from LuckyCalls", payload.dictionaryPayload[@"aps"][@"callerName"]];
//   NSString *handle = payload.dictionaryPayload[@"aps"][@"handle"];

  NSString *uuid = [[[NSUUID UUID] UUIDString] lowercaseString];
  NSString *callerName = payload.dictionaryPayload[@"aps"][@"number"];
  NSString *callType = payload.dictionaryPayload[@"aps"][@"type"];
  NSString *handle = @"Calls";
  BOOL hasVideo = [callType isEqualToString:@"video"] ? YES : NO;
  // --- this is optional, only required if you want to call `completion()` on the js side
  [RNVoipPushNotificationManager addCompletionHandler:uuid completionHandler:completion];

  // --- Process the received push
  [RNVoipPushNotificationManager didReceiveIncomingPushWithPayload:payload forType:(NSString *)type];
//  NSDictionary *extra = [payload.dictionaryPayload valueForKeyPath:@"custom.path.to.data"];

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

  // --- You don't need to call it if you stored `completion()` and will call it on the js side.
  completion();
}

@end

Maybe I made a mistake in it

w4ugit avatar Jan 11 '24 12:01 w4ugit

Can you please add console.log in useEffect just to see how many times you are attaching listeners. Also you can try to set breakpoints in place where this event is firing in xCode

Romick2005 avatar Jan 11 '24 13:01 Romick2005

image

one

w4ugit avatar Jan 11 '24 13:01 w4ugit

Is that possible that you receive 2 voip push notifications? You should debug native objective-C with xCode

Romick2005 avatar Jan 11 '24 15:01 Romick2005

no, I checked it first, push is definitely 1

w4ugit avatar Jan 11 '24 15:01 w4ugit

this is what the xcode log shows when the push comes

2024-01-11 17:37:39.556625+0200 LuckyCalls[693:111874] [native] [RNVoipPushNotificationManager] didReceiveIncomingPushWithPayload payload.dictionaryPayload = {
    aps =     {
        alert = "Hello from APNs";
        badge = 1;
        callerName = Taras;
        handle = 123123123;
        uuid = 123;
    };
    uuid = "27858492-b209-4fb6-9359-825218a76a8b";
}, type = PKPushTypeVoIP
2024-01-11 17:37:39.556914+0200 LuckyCalls[693:111874] [RNCallKeep][reportNewIncomingCall] uuidString = 745ff3d3-fba9-4793-95f4-3dd3ff67a7c0
2024-01-11 17:37:39.557836+0200 LuckyCalls[693:112248] [native] [RNVoipPushNotificationManager] onVoipNotificationCompleted() not found. uuid = 27858492-b209-4fb6-9359-825218a76a8b
2024-01-11 17:37:39.582389+0200 LuckyCalls[693:111874] [RNCallKeep] sendEventWithNameWrapper: RNCallKeepDidDisplayIncomingCall, hasListeners : NO
2024-01-11 17:37:39.582461+0200 LuckyCalls[693:111874] [RNCallKeep][configureAudioSession] Activating audio session
2024-01-11 17:37:43.032228+0200 LuckyCalls[693:111874] [EventDispatcher] Found no UIEvent for backing event of type: 11; contextId: 0xE23307E5
2024-01-11 17:37:43.032572+0200 LuckyCalls[693:111874] [EventDispatcher] Found no UIEvent for backing event of type: 11; contextId: 0xE23307E5
2024-01-11 17:37:43.036057+0200 LuckyCalls[693:111874] [EventDispatcher] Found no UIEvent for backing event of type: 11; contextId: 0xE23307E5
2024-01-11 17:37:44.789032+0200 LuckyCalls[693:111874] [RNCallKeep][CXProviderDelegate][provider:performEndCallAction]
2024-01-11 17:37:44.789161+0200 LuckyCalls[693:111874] [RNCallKeep] sendEventWithNameWrapper: RNCallKeepPerformEndCallAction, hasListeners : NO
2024-01-11 17:37:45.847577+0200 LuckyCalls[693:111874] [RNCallKeep][CXProviderDelegate][provider:performEndCallAction]
2024-01-11 17:37:45.847780+0200 LuckyCalls[693:111874] [RNCallKeep] sendEventWithNameWrapper: RNCallKeepPerformEndCallAction, hasListeners : NO
2024-01-11 17:37:46.006107+0200 LuckyCalls[693:111874] [native] Sending `RNCallKeepDidChangeAudioRoute` with no listeners registered.
2024-01-11 17:37:46.006450+0200 LuckyCalls[693:112253] [javascript] Sending `RNCallKeepDidChangeAudioRoute` with no listeners registered.

w4ugit avatar Jan 11 '24 15:01 w4ugit

So yeah it is coming from native part - [RNCallKeep][CXProviderDelegate][provider:performEndCallAction] x 2 You can try my older forked version that works for me even nowadays. Or try to fix in the lib and then patch it. https://github.com/Romick2005/react-native-voip-push-notification

Romick2005 avatar Jan 11 '24 17:01 Romick2005

I recently was doing some get voip code refactor and I think I know what is your problem. It is because you call voip registration twice: from native code and from js. Native: [RNVoipPushNotificationManager voipRegistration]; JS: VoipPushNotification.registerVoipToken(); // --- register token

So I suggest to call voip registration only on native side and using delayed events from didLoadWithEvents you can get registration voip token on JS side.

Romick2005 avatar Jan 23 '24 21:01 Romick2005

HI, this library using VOIP call for react native app? if i use this mean,can i get voip token and open call kit everything .

karthickrohan avatar Feb 02 '24 13:02 karthickrohan

Yeah, this lib is just to get voip token, that would be used for iOS CallKit.

Romick2005 avatar Feb 02 '24 14:02 Romick2005

HI, this library using VOIP call for react native app? if i use this mean,can i get voip token and open call kit everything .

@karthickrohan you can use react-native-callkeep for opening callkit

dev-rajasekhar avatar Mar 21 '25 12:03 dev-rajasekhar