react-native-callkeep
react-native-callkeep copied to clipboard
didLoadWithEvents always getting RNCallKeepDidDisplayIncomingCall
Bug report
-
[x] I've checked the example to reproduce the issue.
-
Reproduced on:
-
[x] iOS
Description
I have tried to register didLoadWithEvents in index.js and as well as App.js which is my first component. Both are returning RNCallKeepDidDisplayIncomingCall even if i press accept button right when callkit ui appears, i don't get acll accept event name here and if i press accept, i don't get answercall event either
Steps to Reproduce
Versions
- Callkeep: 4.0
- React Native: 0.63.3
- iOS: 14
- Phone model: iPhone 7
Logs
[Thu Nov 26 2020 15:51:10.950] LOG didLoadWithEvents -> events {"data": {"callUUID": "f7f3f338-4c65-416a-893e-522ce1f3de68", "error": "", "fromPushKit": "1", "handle": "Task: Adnana", "hasVideo": "1", "localizedCallerName": "Adnan guild2 (Connecting...)", "payload": {"35video": true, "53video": true, "callId": "rymTxN91PDVWQIcCOp8q", "callUUID": "f7f3f338-4c65-416a-893e-522ce1f3de68", "callerAvatar": "", "callerId": 53, "callerName": "Adnan guild2", "channelId": "...", "recieverId": 35, "status": "incomingCall", "taskId": 711, "title": "Adnana", "type": "video"}, "supportsDTMF": "0", "supportsGrouping": "0", "supportsHolding": "0", "supportsUngrouping": "0"}, "name": "RNCallKeepDidDisplayIncomingCall"}
#import "AppDelegate.h"
#import <React/RCTBridge.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#import <Firebase.h>
#import "RNFirebaseNotifications.h"
#import "RNFirebaseMessaging.h"
#import "RNSplashScreen.h"
#import "RNCallKeep.h"
//VOIP
#import <PushKit/PushKit.h> /* <------ add this line */
#import "RNVoipPushNotificationManager.h" /* <------ add this line */
#ifdef FB_SONARKIT_ENABLED
#import <FlipperKit/FlipperClient.h>
#import <FlipperKitLayoutPlugin/FlipperKitLayoutPlugin.h>
#import <FlipperKitUserDefaultsPlugin/FKUserDefaultsPlugin.h>
#import <FlipperKitNetworkPlugin/FlipperKitNetworkPlugin.h>
#import <SKIOSNetworkPlugin/SKIOSNetworkAdapter.h>
#import <FlipperKitReactPlugin/FlipperKitReactPlugin.h>
//VOIP
static void InitializeFlipper(UIApplication *application) {
FlipperClient *client = [FlipperClient sharedClient];
SKDescriptorMapper *layoutDescriptorMapper = [[SKDescriptorMapper alloc] initWithDefaults];
[client addPlugin:[[FlipperKitLayoutPlugin alloc] initWithRootNode:application withDescriptorMapper:layoutDescriptorMapper]];
[client addPlugin:[[FKUserDefaultsPlugin alloc] initWithSuiteName:nil]];
[client addPlugin:[FlipperKitReactPlugin new]];
[client addPlugin:[[FlipperKitNetworkPlugin alloc] initWithNetworkAdapter:[SKIOSNetworkAdapter new]]];
[client start];
}
#endif
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[FIRApp configure];
[RNFirebaseNotifications configure];
#ifdef FB_SONARKIT_ENABLED
InitializeFlipper(application);
#endif
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
RNVoipPushNotificationManager* voipModule = [bridge moduleForClass:[RNVoipPushNotificationManager class]];
[voipModule voipRegistration];
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
moduleName:@"Artisan"
initialProperties:nil];
rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [UIViewController new];
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
[RNSplashScreen show];
return YES;
}
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
[[RNFirebaseNotifications instance] didReceiveLocalNotification:notification];
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(nonnull NSDictionary *)userInfo
fetchCompletionHandler:(nonnull void (^)(UIBackgroundFetchResult))completionHandler{
[[RNFirebaseNotifications instance] didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
}
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings {
[[RNFirebaseMessaging instance] didRegisterUserNotificationSettings:notificationSettings];
}
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
#else
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif
}
- (BOOL)application:(UIApplication *)application
continueUserActivity:(NSUserActivity *)userActivity
restorationHandler:(void(^)(NSArray * __nullable restorableObjects))restorationHandler
{
return [RNCallKeep application:application
continueUserActivity:userActivity
restorationHandler:restorationHandler];
}
//VOIP
/* Add PushKit delegate method */
// --- Handle updated push credentials
- (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.
}
// --- Handle incoming pushes (for ios <= 10)
- (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(PKPushType)type {
[RNVoipPushNotificationManager didReceiveIncomingPushWithPayload:payload forType:(NSString *)type];
}
// --- Handle incoming pushes (for ios >= 11)
- (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[@"uuid"];
NSString *callerName = [NSString stringWithFormat:@"%@ (Connecting...)", payload.dictionaryPayload[@"callerName"]];
NSString *handle = payload.dictionaryPayload[@"handle"];
NSString *callData = payload.dictionaryPayload[@"callData"];
// --- 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];
// --- You should make sure to report to callkit BEFORE execute `completion()`
// [RNCallKeep reportNewIncomingCall:uuid
// handle:handle
// handleType:@"generic"
// hasVideo:true
// localizedCallerName:callerName
// fromPushKit: YES
// payload:callData];
//
[RNCallKeep reportNewIncomingCall: uuid
handle: handle
handleType: @"generic"
hasVideo: true
localizedCallerName: callerName
supportsHolding: false
supportsDTMF: false
supportsGrouping: false
supportsUngrouping: false
fromPushKit: YES
payload: callData
withCompletionHandler: nil];
// --- You don't need to call it if you stored `completion()` and will call it on the js side.
completion();
}
//VOIP
@end
Just updated my app to latest version of VoipPushNotifications and I am able to receive multiple events of VOIP package correctly but not for CallKeep
@manuquentin sir i'll really appreciate your help here. Any comment would be very useful for us.
Hi, just wanna ask in ios , i send a voip notification. Do i need to build the app/archived or is it working during development?
Im expecting to open/relaunch the app from background/killed?
Thoughts on this please. Thank you
@mikeangelsilva Hey, if you're using APN with VOIP type make sure you're using correct URLs for sending notification i.e for development build you will use development certificate and sendbox URLs, and when you upload to Testflight you'll use production certificates and live URLs of APN service.
Just updated my app to latest version of VoipPushNotifications and I am able to receive multiple events of VOIP package correctly but not for CallKeep
@manuquentin sir i'll really appreciate your help here. Any comment would be very useful for us.
Hi I am having a similar issue. The VOIP works fine, but Callkeep does not. In my case, even didLoadWithEvents is not called. Did you find any solution to this? Thanks for your help!
Same here any luck with solving that? it is just reporting: RNCallKeepDidDisplayIncomingCall even if user tap accept or reject.
RNCallKeepDidDisplayIncomingCall even if user tap accept or reject.
Can you put some log to see how many RNCallKeepDidDisplayIncomingCall
event was triggered? If it's one event for each call, then it should be correct
Yes, it is a single RNCallKeepDidDisplayIncomingCall for each call which is correct. But incorrect or missing behavior is NOT calling a certain listener answer/end or adding those events in didLoadWithEvents array with js was not ready.
I have the same setup and behavior as the bug report describes above.
RNCallKeepDidDisplayIncomingCall even if user tap accept or reject.
Can you put some log to see how many
RNCallKeepDidDisplayIncomingCall
event was triggered? If it's one event for each call, then it should be correct
Also, I tested that the answerCall in Obj-C somehow did not get triggered. I have no idea what is wrong.
Strange that Im using the latest and it likely never happens. Im curious that how did you register the handlers, in hook, or didmount, or directly in the bundle?
I have them directly in the index.js like this:
` RNCallKeep.addEventListener('answerCall', onAnswerCallAction); RNCallKeep.addEventListener('endCall', onEndCallAction); RNCallKeep.addEventListener('didDisplayIncomingCall', onIncomingCallDisplayed);
`
And also I was debugging Obj-C and answerCall was not called for me. Exactly same as for @Stephen-HWJ
Any luck with reproducing the issue? Are you testing on iOS 14.3?
Any luck with reproducing the issue? Are you testing on iOS 14.3?
Not really. I am testing on 14.3
@Stephen-HWJ and you are getting the correct user action event in didLoadWithEvents besides just RNCallKeepDidDisplayIncomingCall? Can you paste or share the code you are using to test?
@Stephen-HWJ Would you mind posting your setup so we can push the issue forward? It is kind of holding us down and I believe more people may experience this issue.
BTW. Guys @namnm @devWaleed any luck with solving this issue?
@Stephen-HWJ Would you mind posting your setup so we can push the issue forward? It is kind of holding us down and I believe more people may experience this issue.
Please see the code:
RNCallKeep.addEventListener(
'didLoadWithEvents',
async (events) => {
const validEvents = compact(events);
let callDataToAdd = null;
let callDataToAnswer = null;
let callDataToReject = null;
let callDataToInitiateCall = null;
each(compact(validEvents), event => {
const { name, data } = event;
if (name === 'RNCallKeepDidDisplayIncomingCall') {
callDataToAdd = data;
}
if (name === 'RNCallKeepPerformAnswerCallAction') {
callDataToAnswer = data;
}
if (name === 'RNCallKeepPerformEndCallAction') {
callDataToReject = data;
}
});
const lastEventName = get(last(validEvents), 'name');
if (lastEventName === 'RNCallKeepDidReceiveStartCallAction') {
callDataToInitiateCall = get(last(validEvents), 'data');
// callDataToAnswer = null;
if (!callDataToReject) {
callDataToAdd = null;
}
}
if (lastEventName === 'RNCallKeepPerformAnswerCallAction') {
callDataToAnswer = get(last(validEvents), 'data');
}
if (callDataToAdd) {
didDisplayIncomingCallEvent(callDataToAdd);
if (callDataToReject) {
cancelCallHandler(callDataToReject);
}
if (callDataToAnswer) {
answerCallEvent(callDataToAnswer);
}
}
if (callDataToInitiateCall) {
// this.onStartCall(callDataToAnswer);
}
});
Same issue.
didLoadWithEvents
only contains RNCallKeepDidDisplayIncomingCall
.
Checked into Objective C, it seems that the CXAnswerCallAction
is not called.
It only appears when I receive a push notif and the app is killed.
There is a race somewhere, if i accept the call before the js loaded, then the AnswerCall
is not reached.
- Callkeep: 4.0.1
- React Native: 0.61.5
- iOS: 14.4
- Phone model: iPhone 8
Reproduction method:
- be sure that your app is killed
- send a push voip notif to your app
- accept the call before js was fully loaded
- The js never receive the
RNCallKeepPerformAnswerCallAction
, even indidLoadWithEvents
When the issue is reproduced:
- i checked the call's value of
hasConnected
fromcallObserver
:- hasEnded is equals to
false
- hasConnected is equals to
false
- hasEnded is equals to
- verified all events received by the module from the beginning , and what i remarked is
sendEventWithNameWrapper
never received theRNCallKeepPerformAnswerCallAction
event
If i wait that js is fully loaded, then the event is correctly received
@devWaleed could you check with the PR if your issue is fixed? thx
@m4r00p Im trying the above PR My forked repo: https://github.com/brekekesoftware/react-native-callkeep
@Jerome91410 @namnm I've just patched this file locally. Yes, the @Jerome91410's fix is addressing this issue perfectly.
Great thanks to all you guys!!!
@Jerome91410 @namnm I've just patched this file locally. Yes, the @Jerome91410's fix is addressing this issue perfectly.
Great thanks to all you guys!!!
Can you explain how to do this?
Our application is blocked by this bug.
@stephanoparaskeva In your package.json you have something like this:
"dependencies": {
...
"react-native-callkeep": "^4.0.1",
...
}
Then change it to
"dependencies": {
...
"react-native-callkeep": "github:Jerome91410/react-native-callkeep#fix-init",
...
}
After that try remove the node_module for sure, npm install
(or yarn install
), then rerun pod install
and rerun the project in your XCode.
@devWaleed could you check with the PR if your issue is fixed? thx
This did not fix the issue for me, using this PR:
"react-native-callkeep": "github:react-native-webrtc/react-native-callkeep#pull/365/head",
Sometimes I see RNCallKeepDidPerfrormAnswerCallAction
Sometimes I do not.
"react-native-callkeep": "github:Jerome91410/react-native-callkeep#fix-init",
@Jerome91410
This did not work either 😔
It works on iPhone 6 but not iPhone 12
EDIT: it sometimes does not work on my iphone 6, it probably works 5-10% of the time.
@stephanoparaskeva After some more test, I can confirm your issue, although Im using the fork it still happens. Not sure how can we fix this?
@namnm @stephanoparaskeva
I do not reproduce anymore the issue with this pr, but checked only on iphone 8 and XR.
Maybe you can provide logs about callkeep and a reproduce method ?
Don't know if there is any impact but i report with the completion handler defined
[RNCallKeep reportNewIncomingCall: uuid
handle: phonenumber
handleType: @"generic"
hasVideo: hasVideo
localizedCallerName: fullname
supportsHolding: YES
supportsDTMF: YES
supportsGrouping: NO
supportsUngrouping: NO
fromPushKit: YES
payload: data
withCompletionHandler: completion];
@Jerome91410 Just tested on iphone6, still happens. Tried again on iphoneXs but can not reproduce. May be because newer phones have more processing power and load the js bridge faster? Then the code may be still having issue.
Have tried with on both IPhone 6 and IPhone 12 Pro and it does not work:
Have tried this with versions:
"react-native-callkeep": "github:brekekesoftware/react-native-callkeep",
"react-native-callkeep": "github:Jerome91410/react-native-callkeep#fix-init",
"react-native-voip-push-notification": "^3.1.0",
@Jerome91410 What logs can I provide you with that'd help you debug my issue, how do I retrieve these logs?
Here is my appdelegate.m
- (BOOL)application:(UIApplication *)application
continueUserActivity:(NSUserActivity *)userActivity
restorationHandler:(void(^)(NSArray * __nullable restorableObjects))restorationHandler
{
return [RNCallKeep application:application
continueUserActivity:userActivity
restorationHandler:restorationHandler];
}
// --- Handle updated push credentials
- (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.
}
// --- Handle incoming pushes
- (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[@"uuid"];
// @"%@ (Connecting...)"
NSString *callerName = [NSString stringWithFormat:@"%@", payload.dictionaryPayload[@"callerName"]];
NSString *handle = payload.dictionaryPayload[@"handle"];
// --- 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];
// --- You should make sure to report to callkit BEFORE execute `completion()`
// RNCallKeep >4.0.0
[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];
}
My code:
useEffect(() => {
RNCallKeep.setup(SETUP_OPTIONS);
registerDeviceForNotifications();
new Sound('ringback.mp3', Sound.MAIN_BUNDLE);
RNCallKeep.setAvailable(true);
RNCallKeep.addEventListener('didDisplayIncomingCall', incoming =>
dispatch(setIncomingCall(incoming))
);
RNCallKeep.addEventListener('didLoadWithEvents', didLoadWithEvents);
RNCallKeep.addEventListener('answerCall', accept);
return () => {
RNCallKeep.removeEventListener('didDisplayIncomingCall');
RNCallKeep.removeEventListener('didLoadWithEvents');
RNCallKeep.removeEventListener('answerCall');
};
}, []);
Reproduction steps:
- Call phone when app is in background/terminated.
- Accept call.
-
didLoadWithEvents
only containsRNCallKeepDidDisplayIncomingCall
What do you think @zxcpoiu ?