Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
w4ugit opened this issue Jan 11, 2024 · 12 comments
Open

Comments

@w4ugit
Copy link

w4ugit commented Jan 11, 2024

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?

@Romick2005
Copy link
Contributor

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.

@w4ugit
Copy link
Author

w4ugit commented Jan 11, 2024

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
Copy link
Author

w4ugit commented Jan 11, 2024

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

@Romick2005
Copy link
Contributor

Romick2005 commented Jan 11, 2024

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

@w4ugit
Copy link
Author

w4ugit commented Jan 11, 2024

image

one

@Romick2005
Copy link
Contributor

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

@w4ugit
Copy link
Author

w4ugit commented Jan 11, 2024

no, I checked it first, push is definitely 1

@w4ugit
Copy link
Author

w4ugit commented Jan 11, 2024

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.

@Romick2005
Copy link
Contributor

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
Copy link
Contributor

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.

@karthickrohan
Copy link

karthickrohan commented Feb 2, 2024

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 .

@Romick2005
Copy link
Contributor

Romick2005 commented Feb 2, 2024

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants