From a4f5046cd3066320362fa1f401fbe5ac80275498 Mon Sep 17 00:00:00 2001 From: Aleksandar Tokarev Date: Mon, 26 Oct 2020 14:42:04 +0100 Subject: [PATCH 1/6] Clean Up the Plugin --- src/ios/CordovaCall.h | 1 + src/ios/CordovaCall.m | 180 +++++++++++++++++++++++++++++------------- 2 files changed, 127 insertions(+), 54 deletions(-) diff --git a/src/ios/CordovaCall.h b/src/ios/CordovaCall.h index dd6db70..9dca162 100644 --- a/src/ios/CordovaCall.h +++ b/src/ios/CordovaCall.h @@ -8,6 +8,7 @@ @property (nonatomic, copy) NSString *VoIPPushCallbackId; @property (nonatomic, copy) NSString *VoIPPushClassName; @property (nonatomic, copy) NSString *VoIPPushMethodName; +@property (nonatomic, copy) NSString *VoIPPushToken; - (void)init:(CDVInvokedUrlCommand*)command; diff --git a/src/ios/CordovaCall.m b/src/ios/CordovaCall.m index 9fdc9dc..0def28c 100644 --- a/src/ios/CordovaCall.m +++ b/src/ios/CordovaCall.m @@ -6,15 +6,23 @@ @implementation CordovaCall @synthesize VoIPPushCallbackId, VoIPPushClassName, VoIPPushMethodName; -BOOL hasVideo = NO; +BOOL hasVideo = YES; NSString* appName; NSString* ringtone; NSString* icon; BOOL includeInRecents = NO; -NSMutableDictionary *callbackIds; +NSMutableDictionary *callbackIds; NSDictionary* pendingCallFromRecents; BOOL monitorAudioRouteChange = NO; BOOL enableDTMF = NO; +BOOL isRinging = NO; +PKPushRegistry *_voipRegistry; + +NSMutableArray* pendingCallResponses; +NSString* const PENDING_RESPONSE_ANSWER = @"pendingResponseAnswer"; +NSString* const PENDING_RESPONSE_REJECT = @"pendingResponseReject"; + +NSString* const KEY_VOIP_PUSH_TOKEN = @"PK_deviceToken"; - (void)pluginInitialize { @@ -45,10 +53,27 @@ - (void)pluginInitialize [callbackIds setObject:[NSMutableArray array] forKey:@"speakerOn"]; [callbackIds setObject:[NSMutableArray array] forKey:@"speakerOff"]; [callbackIds setObject:[NSMutableArray array] forKey:@"DTMF"]; + + // Add call response (answer or reject) to pending if event listeners are not added at the time of responding + pendingCallResponses = [NSMutableArray new]; + //allows user to make call from recents [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receiveCallFromRecents:) name:@"RecentsCallNotification" object:nil]; //detect Audio Route Changes to make speakerOn and speakerOff event handlers [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleAudioRouteChange:) name:AVAudioSessionRouteChangeNotification object:nil]; + + // Initialize PKPushRegistry + //http://stackoverflow.com/questions/27245808/implement-pushkit-and-test-in-development-behavior/28562124#28562124 + dispatch_queue_t mainQueue = dispatch_get_main_queue(); + // Create a push registry object + _voipRegistry = [[PKPushRegistry alloc] initWithQueue: mainQueue]; + // Set the registry's delegate to self + [_voipRegistry setDelegate:(id _Nullable)self]; + // Set the push type to VoIP + _voipRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP]; + + // Read VoIPPushToken from UserDefaults + self.VoIPPushToken = [[NSUserDefaults standardUserDefaults] stringForKey:KEY_VOIP_PUSH_TOKEN]; } // CallKit - Interface @@ -173,7 +198,6 @@ - (void)setVideo:(CDVInvokedUrlCommand*)command - (void)receiveCall:(CDVInvokedUrlCommand*)command { BOOL hasId = ![[command.arguments objectAtIndex:1] isEqual:[NSNull null]]; - CDVPluginResult* pluginResult = nil; NSString* callName = [command.arguments objectAtIndex:0]; NSString* callId = hasId?[command.arguments objectAtIndex:1]:callName; NSUUID *callUUID = [[NSUUID alloc] init]; @@ -193,19 +217,23 @@ - (void)receiveCall:(CDVInvokedUrlCommand*)command callUpdate.supportsUngrouping = NO; callUpdate.supportsHolding = NO; callUpdate.supportsDTMF = enableDTMF; - - [self.provider reportNewIncomingCallWithUUID:callUUID update:callUpdate completion:^(NSError * _Nullable error) { - if(error == nil) { - [self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:@"Incoming call successful"] callbackId:command.callbackId]; - } else { - [self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:[error localizedDescription]] callbackId:command.callbackId]; + if (!isRinging) { + [self.provider reportNewIncomingCallWithUUID:callUUID update:callUpdate completion:^(NSError * _Nullable error) { + if(error == nil) { + isRinging = YES; + [self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:@"Incoming call successful"] callbackId:command.callbackId]; + } else { + [self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:[error localizedDescription]] callbackId:command.callbackId]; + } + }]; + for (id callbackId in callbackIds[@"receiveCall"]) { + CDVPluginResult* pluginResult = nil; + pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:@"receiveCall event called successfully"]; + [pluginResult setKeepCallbackAsBool:YES]; + [self.commandDelegate sendPluginResult:pluginResult callbackId:callbackId]; } - }]; - for (id callbackId in callbackIds[@"receiveCall"]) { - CDVPluginResult* pluginResult = nil; - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:@"receiveCall event called successfully"]; - [pluginResult setKeepCallbackAsBool:YES]; - [self.commandDelegate sendPluginResult:pluginResult callbackId:callbackId]; + } else { + [self endCall:command]; } } else { [self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Caller id can't be empty"] callbackId:command.callbackId]; @@ -259,6 +287,7 @@ - (void)connectCall:(CDVInvokedUrlCommand*)command - (void)endCall:(CDVInvokedUrlCommand*)command { + isRinging = NO; CDVPluginResult* pluginResult = nil; NSArray *calls = self.callController.callObserver.calls; @@ -293,6 +322,16 @@ - (void)registerEvent:(CDVInvokedUrlCommand*)command [pluginResult setKeepCallbackAsBool:YES]; [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; } + + // In case of registerEvent answer or reject called after responding to call, trigger cordova event for the appropriate answer + if ([eventName isEqualToString:@"answer"] && [pendingCallResponses containsObject:PENDING_RESPONSE_ANSWER]) { + [self triggerCordovaEventForCallResponse:@"answer"]; + [pendingCallResponses removeObject:PENDING_RESPONSE_ANSWER]; + } + if ([eventName isEqualToString:@"reject"] && [pendingCallResponses containsObject:PENDING_RESPONSE_REJECT]) { + [self triggerCordovaEventForCallResponse:@"reject"]; + [pendingCallResponses removeObject:PENDING_RESPONSE_REJECT]; + } } - (void)mute:(CDVInvokedUrlCommand*)command @@ -475,19 +514,21 @@ - (void)provider:(CXProvider *)provider didDeactivateAudioSession:(AVAudioSessio - (void)provider:(CXProvider *)provider performAnswerCallAction:(CXAnswerCallAction *)action { + isRinging = NO; [self setupAudioSession]; [action fulfill]; - for (id callbackId in callbackIds[@"answer"]) { - CDVPluginResult* pluginResult = nil; - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:@"answer event called successfully"]; - [pluginResult setKeepCallbackAsBool:YES]; - [self.commandDelegate sendPluginResult:pluginResult callbackId:callbackId]; + if ([callbackIds[@"answer"] count] == 0) { + // callbackId for event not registered, add to pending to trigger on registration + [pendingCallResponses addObject:PENDING_RESPONSE_ANSWER]; + } else { + [self triggerCordovaEventForCallResponse:@"answer"]; } //[action fail]; } - (void)provider:(CXProvider *)provider performEndCallAction:(CXEndCallAction *)action { + isRinging = NO; NSArray *calls = self.callController.callObserver.calls; if([calls count] == 1) { if(calls[0].hasConnected) { @@ -498,11 +539,11 @@ - (void)provider:(CXProvider *)provider performEndCallAction:(CXEndCallAction *) [self.commandDelegate sendPluginResult:pluginResult callbackId:callbackId]; } } else { - for (id callbackId in callbackIds[@"reject"]) { - CDVPluginResult* pluginResult = nil; - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:@"reject event called successfully"]; - [pluginResult setKeepCallbackAsBool:YES]; - [self.commandDelegate sendPluginResult:pluginResult callbackId:callbackId]; + if ([callbackIds[@"reject"] count] == 0) { + // callbackId for event not registered, add to pending to trigger on registration + [pendingCallResponses addObject:PENDING_RESPONSE_REJECT]; + } else { + [self triggerCordovaEventForCallResponse:@"reject"]; } } } @@ -511,6 +552,24 @@ - (void)provider:(CXProvider *)provider performEndCallAction:(CXEndCallAction *) //[action fail]; } +- (void)triggerCordovaEventForCallResponse:(NSString*) response { + if ([response isEqualToString:@"answer"]) { + for (id callbackId in callbackIds[@"answer"]) { + CDVPluginResult* pluginResult = nil; + pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:@"answer event called successfully"]; + [pluginResult setKeepCallbackAsBool:YES]; + [self.commandDelegate sendPluginResult:pluginResult callbackId:callbackId]; + } + } else if ([response isEqualToString:@"reject"]) { + for (id callbackId in callbackIds[@"reject"]) { + CDVPluginResult* pluginResult = nil; + pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:@"reject event called successfully"]; + [pluginResult setKeepCallbackAsBool:YES]; + [self.commandDelegate sendPluginResult:pluginResult callbackId:callbackId]; + } + } +} + - (void)provider:(CXProvider *)provider performSetMutedCallAction:(CXSetMutedCallAction *)action { [action fulfill]; @@ -536,20 +595,31 @@ - (void)provider:(CXProvider *)provider performPlayDTMFCallAction:(CXPlayDTMFCal [self.commandDelegate sendPluginResult:pluginResult callbackId:callbackId]; } } - // PushKit - (void)init:(CDVInvokedUrlCommand*)command { - self.VoIPPushCallbackId = command.callbackId; - NSLog(@"[objC] callbackId: %@", self.VoIPPushCallbackId); + self.VoIPPushCallbackId = command.callbackId; + NSLog(@"[objC] callbackId: %@", self.VoIPPushCallbackId); + + [self sendTokenPluginResult]; +} + +- (void)sendTokenPluginResult { + if (!self.VoIPPushCallbackId || !self.VoIPPushToken) { + return; + } - //http://stackoverflow.com/questions/27245808/implement-pushkit-and-test-in-development-behavior/28562124#28562124 - PKPushRegistry *pushRegistry = [[PKPushRegistry alloc] initWithQueue:dispatch_get_main_queue()]; - pushRegistry.delegate = self; - pushRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP]; + NSMutableDictionary* results = [NSMutableDictionary dictionaryWithCapacity:2]; + [results setObject:self.VoIPPushToken forKey:@"deviceToken"]; + [results setObject:@"true" forKey:@"registration"]; + + CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:results]; + [pluginResult setKeepCallbackAsBool:YES]; + [self.commandDelegate sendPluginResult:pluginResult callbackId:self.VoIPPushCallbackId]; } -- (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(NSString *)type{ +#define PushKit Delegate Methods +- (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(PKPushType)type{ if([credentials.token length] == 0) { NSLog(@"[objC] No device token!"); return; @@ -558,21 +628,17 @@ - (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPush //http://stackoverflow.com/a/9372848/534755 NSLog(@"[objC] Device token: %@", credentials.token); const unsigned *tokenBytes = [credentials.token bytes]; - NSString *sToken = [NSString stringWithFormat:@"%08x%08x%08x%08x%08x%08x%08x%08x", + self.VoIPPushToken = [NSString stringWithFormat:@"%08x%08x%08x%08x%08x%08x%08x%08x", ntohl(tokenBytes[0]), ntohl(tokenBytes[1]), ntohl(tokenBytes[2]), ntohl(tokenBytes[3]), ntohl(tokenBytes[4]), ntohl(tokenBytes[5]), ntohl(tokenBytes[6]), ntohl(tokenBytes[7])]; - - NSMutableDictionary* results = [NSMutableDictionary dictionaryWithCapacity:2]; - [results setObject:sToken forKey:@"deviceToken"]; - [results setObject:@"true" forKey:@"registration"]; - CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:results]; - [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]]; //[pluginResult setKeepCallbackAsBool:YES]; - [self.commandDelegate sendPluginResult:pluginResult callbackId:self.VoIPPushCallbackId]; + // Store VoIPPushToken in UserDefaults + [[NSUserDefaults standardUserDefaults] setObject:self.VoIPPushToken forKey:KEY_VOIP_PUSH_TOKEN]; + + [self sendTokenPluginResult]; } - -- (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(NSString *)type +- (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(PKPushType)type withCompletionHandler:(void (^)(void))completion { NSDictionary *payloadDict = payload.dictionaryPayload[@"aps"]; NSLog(@"[objC] didReceiveIncomingPushWithPayload: %@", payloadDict); @@ -580,32 +646,38 @@ - (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayloa NSString *message = payloadDict[@"alert"]; NSLog(@"[objC] received VoIP message: %@", message); - NSString *data = payload.dictionaryPayload[@"data"]; + NSDictionary *data = payload.dictionaryPayload[@"data"]; NSLog(@"[objC] received data: %@", data); NSMutableDictionary* results = [NSMutableDictionary dictionaryWithCapacity:2]; [results setObject:message forKey:@"function"]; - [results setObject:data forKey:@"extra"]; + [results setObject:@"" forKey:@"extra"]; + + NSObject* caller = [data objectForKey:@"Caller"]; + NSArray* args = [NSArray arrayWithObjects:[caller valueForKey:@"Username"], [caller valueForKey:@"ConnectionId"], nil]; + CDVInvokedUrlCommand* newCommand = [[CDVInvokedUrlCommand alloc] initWithArguments:args callbackId:@"" className:self.VoIPPushClassName methodName:self.VoIPPushMethodName]; + [self receiveCall:newCommand]; @try { - NSError* error; - NSDictionary* json = [NSJSONSerialization JSONObjectWithData:[data dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:&error]; - - NSObject* caller = [json objectForKey:@"Caller"]; - NSArray* args = [NSArray arrayWithObjects:[caller valueForKey:@"Username"], [caller valueForKey:@"ConnectionId"], nil]; + NSError * err; + NSData * jsonData = [NSJSONSerialization dataWithJSONObject:data options:0 error:&err]; + NSString * dataString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; + [results setObject:dataString forKey:@"extra"]; - CDVInvokedUrlCommand* newCommand = [[CDVInvokedUrlCommand alloc] initWithArguments:args callbackId:@"" className:self.VoIPPushClassName methodName:self.VoIPPushMethodName]; - [self receiveCall:newCommand]; } @catch (NSException *exception) { - NSLog(@"[objC] error: %@", exception.reason); + NSLog(@"[objC] error: %@", exception.reason); + CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:exception.reason]; + [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]]; + [self.commandDelegate sendPluginResult:pluginResult callbackId:self.VoIPPushCallbackId]; + return; } @finally { CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:results]; [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]]; [self.commandDelegate sendPluginResult:pluginResult callbackId:self.VoIPPushCallbackId]; + completion(); } } - @end From cac1ffb0aaeb3da1588bb3758c3e61637bb49a64 Mon Sep 17 00:00:00 2001 From: Aleksandar Tokarev Date: Fri, 13 Nov 2020 13:08:51 +0100 Subject: [PATCH 2/6] Add Webhook Notification on Receive Push, Call Accept, Call Decline --- src/ios/CordovaCall.m | 44 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/ios/CordovaCall.m b/src/ios/CordovaCall.m index 0def28c..e06a615 100644 --- a/src/ios/CordovaCall.m +++ b/src/ios/CordovaCall.m @@ -18,6 +18,10 @@ @implementation CordovaCall BOOL isRinging = NO; PKPushRegistry *_voipRegistry; +BOOL isCancelPush = NO; +NSString* callBackUrl; +NSString* callId; + NSMutableArray* pendingCallResponses; NSString* const PENDING_RESPONSE_ANSWER = @"pendingResponseAnswer"; NSString* const PENDING_RESPONSE_REJECT = @"pendingResponseReject"; @@ -517,6 +521,17 @@ - (void)provider:(CXProvider *)provider performAnswerCallAction:(CXAnswerCallAct isRinging = NO; [self setupAudioSession]; [action fulfill]; + + // Notify Webhook that Native Call has been Answered + NSURL *statusUpdateUrl = [NSURL URLWithString:[NSString stringWithFormat:@"%@?id=%@&input=%@", callBackUrl, callId, @"pickup"]]; + NSURLSession *session = [NSURLSession sharedSession]; + [[session dataTaskWithURL:statusUpdateUrl + completionHandler:^(NSData *statusUpdateData, + NSURLResponse *statusUpdateResponse, + NSError *statusUpdateError) { + // handle response + }] resume]; + if ([callbackIds[@"answer"] count] == 0) { // callbackId for event not registered, add to pending to trigger on registration [pendingCallResponses addObject:PENDING_RESPONSE_ANSWER]; @@ -539,6 +554,16 @@ - (void)provider:(CXProvider *)provider performEndCallAction:(CXEndCallAction *) [self.commandDelegate sendPluginResult:pluginResult callbackId:callbackId]; } } else { + // Notify Webhook that Native Call has been Declined + NSURL *statusUpdateUrl = [NSURL URLWithString:[NSString stringWithFormat:@"%@?id=%@&input=%@", callBackUrl, callId, @"declined_callee"]]; + NSURLSession *session = [NSURLSession sharedSession]; + [[session dataTaskWithURL:statusUpdateUrl + completionHandler:^(NSData *statusUpdateData, + NSURLResponse *statusUpdateResponse, + NSError *statusUpdateError) { + // handle response + }] resume]; + if ([callbackIds[@"reject"] count] == 0) { // callbackId for event not registered, add to pending to trigger on registration [pendingCallResponses addObject:PENDING_RESPONSE_REJECT]; @@ -657,6 +682,25 @@ - (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayloa NSArray* args = [NSArray arrayWithObjects:[caller valueForKey:@"Username"], [caller valueForKey:@"ConnectionId"], nil]; CDVInvokedUrlCommand* newCommand = [[CDVInvokedUrlCommand alloc] initWithArguments:args callbackId:@"" className:self.VoIPPushClassName methodName:self.VoIPPushMethodName]; + // Store URL and Call Id so they can be used for call Answer/Reject + callBackUrl = [caller valueForKey:@"CallbackUrl"]; + callId = [caller valueForKey:@"ConnectionId"]; + if ([[caller valueForKey:@"CancelPush"] isEqualToString:@"true"]) { + isCancelPush = YES; + } else { + isCancelPush = NO; + } + + // Notify Webhook that VOIP Push Has been received and app is started + NSURL *statusUpdateUrl = [NSURL URLWithString:[NSString stringWithFormat:@"%@?id=%@&input=%@", callBackUrl, callId, @"connected"]]; + NSURLSession *session = [NSURLSession sharedSession]; + [[session dataTaskWithURL:statusUpdateUrl + completionHandler:^(NSData *statusUpdateData, + NSURLResponse *statusUpdateResponse, + NSError *statusUpdateError) { + // handle response + }] resume]; + [self receiveCall:newCommand]; @try { NSError * err; From c0c5cb32281455fe968c8ae362a5064f42f8b595 Mon Sep 17 00:00:00 2001 From: Aleksandar Tokarev Date: Sun, 15 Nov 2020 00:18:33 +0100 Subject: [PATCH 3/6] Handle Cancel Push --- src/ios/CordovaCall.m | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/src/ios/CordovaCall.m b/src/ios/CordovaCall.m index e06a615..9e37b68 100644 --- a/src/ios/CordovaCall.m +++ b/src/ios/CordovaCall.m @@ -555,14 +555,16 @@ - (void)provider:(CXProvider *)provider performEndCallAction:(CXEndCallAction *) } } else { // Notify Webhook that Native Call has been Declined - NSURL *statusUpdateUrl = [NSURL URLWithString:[NSString stringWithFormat:@"%@?id=%@&input=%@", callBackUrl, callId, @"declined_callee"]]; - NSURLSession *session = [NSURLSession sharedSession]; - [[session dataTaskWithURL:statusUpdateUrl - completionHandler:^(NSData *statusUpdateData, - NSURLResponse *statusUpdateResponse, - NSError *statusUpdateError) { - // handle response - }] resume]; + if (!isCancelPush) { + NSURL *statusUpdateUrl = [NSURL URLWithString:[NSString stringWithFormat:@"%@?id=%@&input=%@", callBackUrl, callId, @"declined_callee"]]; + NSURLSession *session = [NSURLSession sharedSession]; + [[session dataTaskWithURL:statusUpdateUrl + completionHandler:^(NSData *statusUpdateData, + NSURLResponse *statusUpdateResponse, + NSError *statusUpdateError) { + // handle response + }] resume]; + } if ([callbackIds[@"reject"] count] == 0) { // callbackId for event not registered, add to pending to trigger on registration @@ -690,16 +692,17 @@ - (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayloa } else { isCancelPush = NO; } - - // Notify Webhook that VOIP Push Has been received and app is started - NSURL *statusUpdateUrl = [NSURL URLWithString:[NSString stringWithFormat:@"%@?id=%@&input=%@", callBackUrl, callId, @"connected"]]; - NSURLSession *session = [NSURLSession sharedSession]; - [[session dataTaskWithURL:statusUpdateUrl - completionHandler:^(NSData *statusUpdateData, - NSURLResponse *statusUpdateResponse, - NSError *statusUpdateError) { - // handle response - }] resume]; + if (!isCancelPush) { + // Notify Webhook that VOIP Push Has been received and app is started + NSURL *statusUpdateUrl = [NSURL URLWithString:[NSString stringWithFormat:@"%@?id=%@&input=%@", callBackUrl, callId, @"connected"]]; + NSURLSession *session = [NSURLSession sharedSession]; + [[session dataTaskWithURL:statusUpdateUrl + completionHandler:^(NSData *statusUpdateData, + NSURLResponse *statusUpdateResponse, + NSError *statusUpdateError) { + // handle response + }] resume]; + } [self receiveCall:newCommand]; @try { From 59953a35e2d899f4dcf416263c2b39c70c61831e Mon Sep 17 00:00:00 2001 From: Aleksandar Tokarev Date: Fri, 20 Nov 2020 09:25:59 +0100 Subject: [PATCH 4/6] Update Readme --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 7208a26..e22c5de 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,8 @@ +# NOTE +Master branch is not the latest - check "trusted-care-master" for newest code. +Basically master had some PushWoosh stuff for Android from the guy that i forked, and there were naming conflicts for Android on the PushNotification plugin that we are using - https://github.com/phonegap/phonegap-plugin-push, therefore i reverted to the original creator last commit and made changes on top of that in the new branch. +https://github.com/AleksandarTokarev/cordova-plugin-callkit/tree/trusted-care-master + # cordova-plugin-callkit Cordova plugin that enables CallKit + PushKit (iOS) & ConnectionService (Android) functionality to display native UI. From c22110cd3302a6b52c7d40367353ff4b310ff97f Mon Sep 17 00:00:00 2001 From: Aleksandar Tokarev Date: Tue, 1 Dec 2020 12:25:23 +0100 Subject: [PATCH 5/6] Remove Is Ringing Flag --- src/ios/CordovaCall.m | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/ios/CordovaCall.m b/src/ios/CordovaCall.m index 9e37b68..4c2c8a7 100644 --- a/src/ios/CordovaCall.m +++ b/src/ios/CordovaCall.m @@ -15,7 +15,6 @@ @implementation CordovaCall NSDictionary* pendingCallFromRecents; BOOL monitorAudioRouteChange = NO; BOOL enableDTMF = NO; -BOOL isRinging = NO; PKPushRegistry *_voipRegistry; BOOL isCancelPush = NO; @@ -221,10 +220,9 @@ - (void)receiveCall:(CDVInvokedUrlCommand*)command callUpdate.supportsUngrouping = NO; callUpdate.supportsHolding = NO; callUpdate.supportsDTMF = enableDTMF; - if (!isRinging) { + if (!isCancelPush) { [self.provider reportNewIncomingCallWithUUID:callUUID update:callUpdate completion:^(NSError * _Nullable error) { if(error == nil) { - isRinging = YES; [self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:@"Incoming call successful"] callbackId:command.callbackId]; } else { [self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:[error localizedDescription]] callbackId:command.callbackId]; @@ -237,7 +235,11 @@ - (void)receiveCall:(CDVInvokedUrlCommand*)command [self.commandDelegate sendPluginResult:pluginResult callbackId:callbackId]; } } else { - [self endCall:command]; + NSArray *calls = self.callController.callObserver.calls; + if([calls count] == 1) { + [self.provider reportCallWithUUID:calls[0].UUID endedAtDate:nil reason:CXCallEndedReasonRemoteEnded]; + } + } } else { [self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Caller id can't be empty"] callbackId:command.callbackId]; @@ -291,12 +293,10 @@ - (void)connectCall:(CDVInvokedUrlCommand*)command - (void)endCall:(CDVInvokedUrlCommand*)command { - isRinging = NO; CDVPluginResult* pluginResult = nil; NSArray *calls = self.callController.callObserver.calls; if([calls count] == 1) { - //[self.provider reportCallWithUUID:calls[0].UUID endedAtDate:nil reason:CXCallEndedReasonRemoteEnded]; CXEndCallAction *endCallAction = [[CXEndCallAction alloc] initWithCallUUID:calls[0].UUID]; CXTransaction *transaction = [[CXTransaction alloc] initWithAction:endCallAction]; [self.callController requestTransaction:transaction completion:^(NSError * _Nullable error) { @@ -518,7 +518,6 @@ - (void)provider:(CXProvider *)provider didDeactivateAudioSession:(AVAudioSessio - (void)provider:(CXProvider *)provider performAnswerCallAction:(CXAnswerCallAction *)action { - isRinging = NO; [self setupAudioSession]; [action fulfill]; @@ -543,7 +542,6 @@ - (void)provider:(CXProvider *)provider performAnswerCallAction:(CXAnswerCallAct - (void)provider:(CXProvider *)provider performEndCallAction:(CXEndCallAction *)action { - isRinging = NO; NSArray *calls = self.callController.callObserver.calls; if([calls count] == 1) { if(calls[0].hasConnected) { From 1906e36e900fa3dd500d9a7cc174332d6dfa6caa Mon Sep 17 00:00:00 2001 From: Daniel Dornhardt Date: Mon, 2 May 2022 12:13:44 +0300 Subject: [PATCH 6/6] Hopefully this fixes our builds not being shown as a phone calling option anymore. --- src/ios/CordovaCall.m | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ios/CordovaCall.m b/src/ios/CordovaCall.m index 4c2c8a7..1f0471b 100644 --- a/src/ios/CordovaCall.m +++ b/src/ios/CordovaCall.m @@ -35,7 +35,7 @@ - (void)pluginInitialize providerConfiguration.maximumCallGroups = 1; providerConfiguration.maximumCallsPerCallGroup = 1; NSMutableSet *handleTypes = [[NSMutableSet alloc] init]; - [handleTypes addObject:@(CXHandleTypePhoneNumber)]; + [handleTypes addObject:@(CXHandleTypeGeneric)]; providerConfiguration.supportedHandleTypes = handleTypes; providerConfiguration.supportsVideo = YES; if (@available(iOS 11.0, *)) { @@ -95,7 +95,7 @@ - (void)updateProviderConfig providerConfiguration.iconTemplateImageData = iconData; } NSMutableSet *handleTypes = [[NSMutableSet alloc] init]; - [handleTypes addObject:@(CXHandleTypePhoneNumber)]; + [handleTypes addObject:@(CXHandleTypeGeneric)]; providerConfiguration.supportedHandleTypes = handleTypes; providerConfiguration.supportsVideo = hasVideo; if (@available(iOS 11.0, *)) { @@ -211,7 +211,7 @@ - (void)receiveCall:(CDVInvokedUrlCommand*)command } if (callName != nil && [callName length] > 0) { - CXHandle *handle = [[CXHandle alloc] initWithType:CXHandleTypePhoneNumber value:callId]; + CXHandle *handle = [[CXHandle alloc] initWithType:CXHandleTypeGeneric value:callId]; CXCallUpdate *callUpdate = [[CXCallUpdate alloc] init]; callUpdate.remoteHandle = handle; callUpdate.hasVideo = hasVideo; @@ -259,7 +259,7 @@ - (void)sendCall:(CDVInvokedUrlCommand*)command } if (callName != nil && [callName length] > 0) { - CXHandle *handle = [[CXHandle alloc] initWithType:CXHandleTypePhoneNumber value:callId]; + CXHandle *handle = [[CXHandle alloc] initWithType:CXHandleTypeGeneric value:callId]; CXStartCallAction *startCallAction = [[CXStartCallAction alloc] initWithCallUUID:callUUID handle:handle]; startCallAction.contactIdentifier = callName; startCallAction.video = hasVideo; @@ -432,7 +432,7 @@ - (void)receiveCallFromRecents:(NSNotification *) notification NSString* callID = notification.object[@"callId"]; NSString* callName = notification.object[@"callName"]; NSUUID *callUUID = [[NSUUID alloc] init]; - CXHandle *handle = [[CXHandle alloc] initWithType:CXHandleTypePhoneNumber value:callID]; + CXHandle *handle = [[CXHandle alloc] initWithType:CXHandleTypeGeneric value:callID]; CXStartCallAction *startCallAction = [[CXStartCallAction alloc] initWithCallUUID:callUUID handle:handle]; startCallAction.video = [notification.object[@"isVideo"] boolValue]?YES:NO; startCallAction.contactIdentifier = callName;