react-native-twilio-programmable-voice
react-native-twilio-programmable-voice copied to clipboard
Fix can not receive call from background when app was killed on IOS 14
Hi! 👋
Firstly, thanks for your work on this project! 🙂
Today I used patch-package to patch [email protected]
for the project I'm working on.
Here is the diff that solved my problem:
diff --git a/node_modules/react-native-twilio-programmable-voice/ios/RNTwilioVoice/RNTwilioVoice.h b/node_modules/react-native-twilio-programmable-voice/ios/RNTwilioVoice/RNTwilioVoice.h
index 117b1d6..9152068 100644
--- a/node_modules/react-native-twilio-programmable-voice/ios/RNTwilioVoice/RNTwilioVoice.h
+++ b/node_modules/react-native-twilio-programmable-voice/ios/RNTwilioVoice/RNTwilioVoice.h
@@ -7,5 +7,7 @@
#import <React/RCTEventEmitter.h>
@interface RNTwilioVoice : RCTEventEmitter <RCTBridgeModule>
-
+- (void) configCallKit: (NSDictionary *)params;
+- (void) reRegisterWithTwilioVoice;
+- (void) initPushRegistry;
@end
diff --git a/node_modules/react-native-twilio-programmable-voice/ios/RNTwilioVoice/RNTwilioVoice.m b/node_modules/react-native-twilio-programmable-voice/ios/RNTwilioVoice/RNTwilioVoice.m
index 711ad26..7a21138 100644
--- a/node_modules/react-native-twilio-programmable-voice/ios/RNTwilioVoice/RNTwilioVoice.m
+++ b/node_modules/react-native-twilio-programmable-voice/ios/RNTwilioVoice/RNTwilioVoice.m
@@ -72,36 +72,7 @@ RCT_EXPORT_METHOD(initWithAccessToken:(NSString *)token) {
}
RCT_EXPORT_METHOD(configureCallKit: (NSDictionary *)params) {
- if (self.callKitCallController == nil) {
- /*
- * The important thing to remember when providing a TVOAudioDevice is that the device must be set
- * before performing any other actions with the SDK (such as connecting a Call, or accepting an incoming Call).
- * In this case we've already initialized our own `TVODefaultAudioDevice` instance which we will now set.
- */
- self.audioDevice = [TVODefaultAudioDevice audioDevice];
- TwilioVoice.audioDevice = self.audioDevice;
-
- self.activeCallInvites = [NSMutableDictionary dictionary];
- self.activeCalls = [NSMutableDictionary dictionary];
-
- _settings = [[NSMutableDictionary alloc] initWithDictionary:params];
- CXProviderConfiguration *configuration = [[CXProviderConfiguration alloc] initWithLocalizedName:params[@"appName"]];
- configuration.maximumCallGroups = 1;
- configuration.maximumCallsPerCallGroup = 1;
- if (_settings[@"imageName"]) {
- configuration.iconTemplateImageData = UIImagePNGRepresentation([UIImage imageNamed:_settings[@"imageName"]]);
- }
- if (_settings[@"ringtoneSound"]) {
- configuration.ringtoneSound = _settings[@"ringtoneSound"];
- }
-
- _callKitProvider = [[CXProvider alloc] initWithConfiguration:configuration];
- [_callKitProvider setDelegate:self queue:nil];
-
- NSLog(@"CallKit Initialized");
-
- self.callKitCallController = [[CXCallController alloc] init];
- }
+ [self configCallKit:params];
}
RCT_EXPORT_METHOD(connect: (NSDictionary *)params) {
@@ -210,11 +181,77 @@ RCT_REMAP_METHOD(getCallInvite,
}
- (void)initPushRegistry {
self.voipRegistry = [[PKPushRegistry alloc] initWithQueue:dispatch_get_main_queue()];
self.voipRegistry.delegate = self;
self.voipRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP];
}
+
+- (void) configCallKit: (NSDictionary *)params {
+ if (self.callKitCallController == nil) {
+ /*
+ * The important thing to remember when providing a TVOAudioDevice is that the device must be set
+ * before performing any other actions with the SDK (such as connecting a Call, or accepting an incoming Call).
+ * In this case we've already initialized our own `TVODefaultAudioDevice` instance which we will now set.
+ */
+ self.audioDevice = [TVODefaultAudioDevice audioDevice];
+ TwilioVoice.audioDevice = self.audioDevice;
+
+ self.activeCallInvites = [NSMutableDictionary dictionary];
+ self.activeCalls = [NSMutableDictionary dictionary];
+
+ _settings = [[NSMutableDictionary alloc] initWithDictionary:params];
+ CXProviderConfiguration *configuration = [[CXProviderConfiguration alloc] initWithLocalizedName:params[@"appName"]];
+ configuration.maximumCallGroups = 1;
+ configuration.maximumCallsPerCallGroup = 1;
+ if (_settings[@"imageName"]) {
+ configuration.iconTemplateImageData = UIImagePNGRepresentation([UIImage imageNamed:_settings[@"imageName"]]);
+ }
+ if (_settings[@"ringtoneSound"]) {
+ configuration.ringtoneSound = _settings[@"ringtoneSound"];
+ }
+
+ _callKitProvider = [[CXProvider alloc] initWithConfiguration:configuration];
+ [_callKitProvider setDelegate:self queue:nil];
+
+ NSLog(@"CallKit Initialized");
+
+ self.callKitCallController = [[CXCallController alloc] init];
+ }
+}
+
+- (void) reRegisterWithTwilioVoice {
+ NSString *accessToken = [self fetchAccessToken];
+ NSString *cachedDeviceToken = [[NSUserDefaults standardUserDefaults] objectForKey:kCachedDeviceToken];
+ NSLog(@"TwilioVoice accessToken: %@", [NSString stringWithFormat:@"%@",accessToken]);
+ NSLog(@"TwilioVoice cachedDeviceToken: %@", [NSString stringWithFormat:@"%@",cachedDeviceToken]);
+ if (cachedDeviceToken.length > 0) {
+ [TwilioVoice registerWithAccessToken:accessToken
+ deviceToken:cachedDeviceToken
+ completion:^(NSError *error) {
+ if (error) {
+ NSLog(@"An error occurred while re-registering: %@", [error localizedDescription]);
+ NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
+ [params setObject:[error localizedDescription] forKey:@"err"];
+
+ [self sendEventWithName:@"deviceNotReady" body:params];
+ }
+ else {
+ NSLog(@"Successfully re-registered for VoIP push notifications.");
+
+ /*
+ * Save the device token after successfully registered.
+ */
+ [[NSUserDefaults standardUserDefaults] setObject:cachedDeviceToken forKey:kCachedDeviceToken];
+ [self sendEventWithName:@"deviceReady" body:nil];
+ }
+ }];
+
+ }
+
+}
+
And then AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
...
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
_rnTwilioVoice = [bridge moduleForClass:[RNTwilioVoice class]];
[_rnTwilioVoice initPushRegistry];
[_rnTwilioVoice reRegisterWithTwilioVoice];
NSDictionary *configCallkit = @{@"appName": @"AppName"};
[_rnTwilioVoice configCallKit:configCallkit];
// --- Voip Push Notification
// ===== (THIS IS OPTIONAL BUT RECOMMENDED) =====
// --- register VoipPushNotification here ASAP rather than in JS. Doing this from the JS side may be too slow for some use cases
// --- see: https://github.com/react-native-webrtc/react-native-voip-push-notification/issues/59#issuecomment-691685841
[RNVoipPushNotificationManager voipRegistration];
...
return YES;
}
@vuletuanbt Are you running into issues with maintaining an up-to-date push token with this whole cachedDeviceToken
/accessToken
thing?
I solved the issue by removing the if
statement that compares them and just registering the token every time (which I believe is best practice per Apple's recommendations. Perhaps your solution addresses this issue?