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

Fix can not receive call from background when app was killed on IOS 14 #190

Open
vuletuanbt opened this issue Mar 11, 2021 · 1 comment
Open

Comments

@vuletuanbt
Copy link

vuletuanbt commented Mar 11, 2021

Hi! 👋

Firstly, thanks for your work on this project! 🙂

Today I used patch-package to patch react-native-twilio-programmable-voice@4.3.1 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 vuletuanbt changed the title Fix can not receive call from background when app was killed on IOS Fix can not receive call from background when app was killed on IOS 14 Mar 11, 2021
@danstepanov
Copy link

@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?

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

2 participants