Skip to content

Commit 030e48f

Browse files
authored
Merge pull request #86 from r0b0t3d/ios-13
[ios-13] add new class method to report incoming call when receiving voip push
2 parents 824a602 + 1fe42bf commit 030e48f

File tree

3 files changed

+120
-60
lines changed

3 files changed

+120
-60
lines changed

README.md

+29-2
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ RNCallKeep.addEventListener('didActivateAudioSession', () => {
423423
Callback for `RNCallKeep.displayIncomingCall`
424424

425425
```js
426-
RNCallKeep.addEventListener('didDisplayIncomingCall', ({ error }) => {
426+
RNCallKeep.addEventListener('didDisplayIncomingCall', ({ error, uuid, handle, localizedCallerName, fromPushKit }) => {
427427
// you might want to do following things when receiving this event:
428428
// - Start playing ringback if it is an outgoing call
429429
});
@@ -580,7 +580,7 @@ class RNCallKeepExample extends React.Component {
580580
onDTMFAction = (data) => {
581581
let { digits, callUUID } = data;
582582
// Called when the system or user performs a DTMF action
583-
}
583+
};
584584

585585
audioSessionActivated = (data) => {
586586
// you might want to do following things when receiving this event:
@@ -600,6 +600,33 @@ class RNCallKeepExample extends React.Component {
600600
}
601601
```
602602

603+
## Receiving a call when the application is not reachable.
604+
605+
In some case your application can be unreachable :
606+
- when the user kill the application
607+
- when it's in background since a long time (eg: after ~5mn the os will kill all connections).
608+
609+
To be able to wake up your application to display the incoming call, you can use [https://github.com/ianlin/react-native-voip-push-notification](react-native-voip-push-notification) on iOS or BackgroundMessaging from [react-native-firebase](https://rnfirebase.io/docs/v5.x.x/messaging/receiving-messages#4)-(Optional)(Android-only)-Listen-for-FCM-messages-in-the-background).
610+
611+
You have to send a push to your application, like with Firebase for Android and with a library supporting PushKit pushes for iOS.
612+
613+
### PushKit
614+
615+
Since iOS 13, you'll have to report the incoming calls that wakes up your application, like in your `AppDelegate.m` :
616+
617+
```objective-c
618+
- (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(PKPushType)type withCompletionHandler:(void (^)(void))completion {
619+
// Process the received push
620+
[RNVoipPushNotificationManager didReceiveIncomingPushWithPayload:payload forType:(NSString *)type];
621+
622+
// Retrieve information like handle and callerName here
623+
624+
[RNCallKeep reportNewIncomingCall:uuid handle:handle handleType:@"generic" hasVideo:false localizedCallerName:callerName fromPushKit: YES];
625+
626+
completion();
627+
}
628+
```
629+
603630
## Debug
604631

605632
### Android

ios/RNCallKeep/RNCallKeep.h

+6
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,10 @@
2727
continueUserActivity:(NSUserActivity *)userActivity
2828
restorationHandler:(void(^)(NSArray * __nullable restorableObjects))restorationHandler;
2929

30+
+ (void)reportNewIncomingCall:(NSString *)uuidString
31+
handle:(NSString *)handle
32+
handleType:(NSString *)handleType
33+
hasVideo:(BOOL)hasVideo
34+
localizedCallerName:(NSString * _Nullable)localizedCallerName
35+
fromPushKit:(BOOL)fromPushKit;
3036
@end

ios/RNCallKeep/RNCallKeep.m

+85-58
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,12 @@
3535

3636
@implementation RNCallKeep
3737
{
38-
NSMutableDictionary *_settings;
3938
NSOperatingSystemVersion _version;
4039
BOOL _isStartCallActionEventListenerAdded;
4140
}
4241

42+
static CXProvider* sharedProvider;
43+
4344
// should initialise in AppDelegate.m
4445
RCT_EXPORT_MODULE()
4546

@@ -73,23 +74,31 @@ - (void)dealloc
7374
if (self.callKeepProvider != nil) {
7475
[self.callKeepProvider invalidate];
7576
}
77+
sharedProvider = nil;
7678
}
7779

7880
// Override method of RCTEventEmitter
7981
- (NSArray<NSString *> *)supportedEvents
8082
{
8183
return @[
82-
RNCallKeepDidReceiveStartCallAction,
83-
RNCallKeepPerformAnswerCallAction,
84-
RNCallKeepPerformEndCallAction,
85-
RNCallKeepDidActivateAudioSession,
86-
RNCallKeepDidDeactivateAudioSession,
87-
RNCallKeepDidDisplayIncomingCall,
88-
RNCallKeepDidPerformSetMutedCallAction,
89-
RNCallKeepPerformPlayDTMFCallAction,
90-
RNCallKeepDidToggleHoldAction,
91-
RNCallKeepProviderReset
92-
];
84+
RNCallKeepDidReceiveStartCallAction,
85+
RNCallKeepPerformAnswerCallAction,
86+
RNCallKeepPerformEndCallAction,
87+
RNCallKeepDidActivateAudioSession,
88+
RNCallKeepDidDeactivateAudioSession,
89+
RNCallKeepDidDisplayIncomingCall,
90+
RNCallKeepDidPerformSetMutedCallAction,
91+
RNCallKeepPerformPlayDTMFCallAction,
92+
RNCallKeepDidToggleHoldAction,
93+
RNCallKeepProviderReset
94+
];
95+
}
96+
97+
+ (void)initCallKitProvider {
98+
if (sharedProvider == nil) {
99+
NSDictionary *settings = [[NSUserDefaults standardUserDefaults] dictionaryForKey:@"RNCallKeepSettings"];
100+
sharedProvider = [[CXProvider alloc] initWithConfiguration:[RNCallKeep getProviderConfiguration:settings]];
101+
}
93102
}
94103

95104
RCT_EXPORT_METHOD(setup:(NSDictionary *)options)
@@ -99,8 +108,14 @@ - (void)dealloc
99108
#endif
100109
_version = [[[NSProcessInfo alloc] init] operatingSystemVersion];
101110
self.callKeepCallController = [[CXCallController alloc] init];
102-
_settings = [[NSMutableDictionary alloc] initWithDictionary:options];
103-
self.callKeepProvider = [[CXProvider alloc] initWithConfiguration:[self getProviderConfiguration]];
111+
NSDictionary *settings = [[NSMutableDictionary alloc] initWithDictionary:options];
112+
// Store settings in NSUserDefault
113+
[[NSUserDefaults standardUserDefaults] setObject:settings forKey:@"RNCallKeepSettings"];
114+
[[NSUserDefaults standardUserDefaults] synchronize];
115+
116+
[RNCallKeep initCallKitProvider];
117+
118+
self.callKeepProvider = sharedProvider;
104119
[self.callKeepProvider setDelegate:self queue:nil];
105120
}
106121

@@ -134,29 +149,7 @@ - (void)dealloc
134149
hasVideo:(BOOL)hasVideo
135150
localizedCallerName:(NSString * _Nullable)localizedCallerName)
136151
{
137-
#ifdef DEBUG
138-
NSLog(@"[RNCallKeep][displayIncomingCall] uuidString = %@", uuidString);
139-
#endif
140-
int _handleType = [self getHandleType:handleType];
141-
NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:uuidString];
142-
CXCallUpdate *callUpdate = [[CXCallUpdate alloc] init];
143-
callUpdate.remoteHandle = [[CXHandle alloc] initWithType:_handleType value:handle];
144-
callUpdate.supportsDTMF = YES;
145-
callUpdate.supportsHolding = YES;
146-
callUpdate.supportsGrouping = YES;
147-
callUpdate.supportsUngrouping = YES;
148-
callUpdate.hasVideo = hasVideo;
149-
callUpdate.localizedCallerName = localizedCallerName;
150-
151-
[self.callKeepProvider reportNewIncomingCallWithUUID:uuid update:callUpdate completion:^(NSError * _Nullable error) {
152-
[self sendEventWithName:RNCallKeepDidDisplayIncomingCall body:@{ @"error": error ? error.localizedDescription : @"" }];
153-
if (error == nil) {
154-
// Workaround per https://forums.developer.apple.com/message/169511
155-
if ([self lessThanIos10_2]) {
156-
[self configureAudioSession];
157-
}
158-
}
159-
}];
152+
[RNCallKeep reportNewIncomingCall: uuidString handle:handle handleType:handleType hasVideo:hasVideo localizedCallerName:localizedCallerName fromPushKit: NO];
160153
}
161154

162155
RCT_EXPORT_METHOD(startCall:(NSString *)uuidString
@@ -168,7 +161,7 @@ - (void)dealloc
168161
#ifdef DEBUG
169162
NSLog(@"[RNCallKeep][startCall] uuidString = %@", uuidString);
170163
#endif
171-
int _handleType = [self getHandleType:handleType];
164+
int _handleType = [RNCallKeep getHandleType:handleType];
172165
NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:uuidString];
173166
CXHandle *callHandle = [[CXHandle alloc] initWithType:_handleType value:handle];
174167
CXStartCallAction *startCallAction = [[CXStartCallAction alloc] initWithCallUUID:uuid handle:callHandle];
@@ -325,6 +318,40 @@ - (void)requestTransaction:(CXTransaction *)transaction
325318
}];
326319
}
327320

321+
+ (void)reportNewIncomingCall:(NSString *)uuidString
322+
handle:(NSString *)handle
323+
handleType:(NSString *)handleType
324+
hasVideo:(BOOL)hasVideo
325+
localizedCallerName:(NSString * _Nullable)localizedCallerName
326+
fromPushKit:(BOOL)fromPushKit
327+
{
328+
#ifdef DEBUG
329+
NSLog(@"[RNCallKeep][reportNewIncomingCall] uuidString = %@", uuidString);
330+
#endif
331+
int _handleType = [RNCallKeep getHandleType:handleType];
332+
NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:uuidString];
333+
CXCallUpdate *callUpdate = [[CXCallUpdate alloc] init];
334+
callUpdate.remoteHandle = [[CXHandle alloc] initWithType:_handleType value:handle];
335+
callUpdate.supportsDTMF = YES;
336+
callUpdate.supportsHolding = YES;
337+
callUpdate.supportsGrouping = YES;
338+
callUpdate.supportsUngrouping = YES;
339+
callUpdate.hasVideo = hasVideo;
340+
callUpdate.localizedCallerName = localizedCallerName;
341+
342+
[RNCallKeep initCallKitProvider];
343+
[sharedProvider reportNewIncomingCallWithUUID:uuid update:callUpdate completion:^(NSError * _Nullable error) {
344+
RNCallKeep *callKeep = [RNCallKeep allocWithZone: nil];
345+
[callKeep sendEventWithName:RNCallKeepDidDisplayIncomingCall body:@{ @"error": error ? error.localizedDescription : @"", @"callUUID": uuidString, @"handle": handle, @"localizedCallerName": localizedCallerName, @"fromPushKit": fromPushKit }];
346+
if (error == nil) {
347+
// Workaround per https://forums.developer.apple.com/message/169511
348+
if ([callKeep lessThanIos10_2]) {
349+
[callKeep configureAudioSession];
350+
}
351+
}
352+
}];
353+
}
354+
328355
- (BOOL)lessThanIos10_2
329356
{
330357
if (_version.majorVersion < 10) {
@@ -336,7 +363,7 @@ - (BOOL)lessThanIos10_2
336363
}
337364
}
338365

339-
- (int)getHandleType:(NSString *)handleType
366+
+ (int)getHandleType:(NSString *)handleType
340367
{
341368
int _handleType;
342369
if ([handleType isEqualToString:@"generic"]) {
@@ -351,30 +378,30 @@ - (int)getHandleType:(NSString *)handleType
351378
return _handleType;
352379
}
353380

354-
- (CXProviderConfiguration *)getProviderConfiguration
381+
+ (CXProviderConfiguration *)getProviderConfiguration:(NSDictionary*)settings
355382
{
356383
#ifdef DEBUG
357384
NSLog(@"[RNCallKeep][getProviderConfiguration]");
358385
#endif
359-
CXProviderConfiguration *providerConfiguration = [[CXProviderConfiguration alloc] initWithLocalizedName:_settings[@"appName"]];
386+
CXProviderConfiguration *providerConfiguration = [[CXProviderConfiguration alloc] initWithLocalizedName:settings[@"appName"]];
360387
providerConfiguration.supportsVideo = YES;
361388
providerConfiguration.maximumCallGroups = 3;
362389
providerConfiguration.maximumCallsPerCallGroup = 1;
363390
providerConfiguration.supportedHandleTypes = [NSSet setWithObjects:[NSNumber numberWithInteger:CXHandleTypePhoneNumber], nil];
364-
if (_settings[@"supportsVideo"]) {
365-
providerConfiguration.supportsVideo = _settings[@"supportsVideo"];
391+
if (settings[@"supportsVideo"]) {
392+
providerConfiguration.supportsVideo = settings[@"supportsVideo"];
366393
}
367-
if (_settings[@"maximumCallGroups"]) {
368-
providerConfiguration.maximumCallGroups = [_settings[@"maximumCallGroups"] integerValue];
394+
if (settings[@"maximumCallGroups"]) {
395+
providerConfiguration.maximumCallGroups = [settings[@"maximumCallGroups"] integerValue];
369396
}
370-
if (_settings[@"maximumCallsPerCallGroup"]) {
371-
providerConfiguration.maximumCallsPerCallGroup = [_settings[@"maximumCallsPerCallGroup"] integerValue];
397+
if (settings[@"maximumCallsPerCallGroup"]) {
398+
providerConfiguration.maximumCallsPerCallGroup = [settings[@"maximumCallsPerCallGroup"] integerValue];
372399
}
373-
if (_settings[@"imageName"]) {
374-
providerConfiguration.iconTemplateImageData = UIImagePNGRepresentation([UIImage imageNamed:_settings[@"imageName"]]);
400+
if (settings[@"imageName"]) {
401+
providerConfiguration.iconTemplateImageData = UIImagePNGRepresentation([UIImage imageNamed:settings[@"imageName"]]);
375402
}
376-
if (_settings[@"ringtoneSound"]) {
377-
providerConfiguration.ringtoneSound = _settings[@"ringtoneSound"];
403+
if (settings[@"ringtoneSound"]) {
404+
providerConfiguration.ringtoneSound = settings[@"ringtoneSound"];
378405
}
379406
return providerConfiguration;
380407
}
@@ -449,9 +476,9 @@ + (BOOL)application:(UIApplication *)application
449476

450477
if (handle != nil && handle.length > 0 ){
451478
NSDictionary *userInfo = @{
452-
@"handle": handle,
453-
@"video": @(isVideoCall)
454-
};
479+
@"handle": handle,
480+
@"video": @(isVideoCall)
481+
};
455482

456483
RNCallKeep *callKeep = [RNCallKeep allocWithZone: nil];
457484
[callKeep handleStartCallNotification: userInfo];
@@ -583,10 +610,10 @@ - (void)provider:(CXProvider *)provider didActivateAudioSession:(AVAudioSession
583610
NSLog(@"[RNCallKeep][CXProviderDelegate][provider:didActivateAudioSession]");
584611
#endif
585612
NSDictionary *userInfo
586-
= @{
587-
AVAudioSessionInterruptionTypeKey: [NSNumber numberWithInt:AVAudioSessionInterruptionTypeEnded],
588-
AVAudioSessionInterruptionOptionKey: [NSNumber numberWithInt:AVAudioSessionInterruptionOptionShouldResume]
589-
};
613+
= @{
614+
AVAudioSessionInterruptionTypeKey: [NSNumber numberWithInt:AVAudioSessionInterruptionTypeEnded],
615+
AVAudioSessionInterruptionOptionKey: [NSNumber numberWithInt:AVAudioSessionInterruptionOptionShouldResume]
616+
};
590617
[[NSNotificationCenter defaultCenter] postNotificationName:AVAudioSessionInterruptionNotification object:nil userInfo:userInfo];
591618

592619
[self configureAudioSession];

0 commit comments

Comments
 (0)