From 19413afb893201e6fe2c53eded54fdd732bedb48 Mon Sep 17 00:00:00 2001 From: Jonas Swiatek Date: Mon, 5 Apr 2021 15:39:28 +0200 Subject: [PATCH 1/4] Implemented support for setup in AppDelegate --- ios/RNCallKeep/RNCallKeep.h | 2 ++ ios/RNCallKeep/RNCallKeep.m | 31 ++++++++++++++++++++++++------- package.json | 2 +- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/ios/RNCallKeep/RNCallKeep.h b/ios/RNCallKeep/RNCallKeep.h index 47ce98b3..c8e7bbdf 100644 --- a/ios/RNCallKeep/RNCallKeep.h +++ b/ios/RNCallKeep/RNCallKeep.h @@ -45,4 +45,6 @@ continueUserActivity:(NSUserActivity *)userActivity + (BOOL)isCallActive:(NSString *)uuidString; ++ (void)setup:(NSDictionary *)options; + @end diff --git a/ios/RNCallKeep/RNCallKeep.m b/ios/RNCallKeep/RNCallKeep.m index 86b64882..0c891a98 100644 --- a/ios/RNCallKeep/RNCallKeep.m +++ b/ios/RNCallKeep/RNCallKeep.m @@ -41,6 +41,7 @@ @implementation RNCallKeep BOOL _isStartCallActionEventListenerAdded; bool _hasListeners; NSMutableArray *_delayedEvents; + bool _isSetup; } static CXProvider* sharedProvider; @@ -54,8 +55,10 @@ - (instancetype)init NSLog(@"[RNCallKeep][init]"); #endif if (self = [super init]) { - _isStartCallActionEventListenerAdded = NO; - _delayedEvents = [NSMutableArray array]; + if (_delayedEvents == nil) { + _isStartCallActionEventListenerAdded = NO; + _delayedEvents = [NSMutableArray array]; + } } return self; } @@ -118,10 +121,10 @@ - (void)sendEventWithNameWrapper:(NSString *)name body:(id)body { if (_hasListeners) { [self sendEventWithName:name body:body]; } else { - NSDictionary *dictionary = @{ - @"name": name, - @"data": body - }; + NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys: + name, @"name", + body, @"data", + nil]; [_delayedEvents addObject:dictionary]; } } @@ -133,8 +136,20 @@ + (void)initCallKitProvider { } } ++ (void)setup:(NSDictionary *)options { + RNCallKeep *callKeep = [RNCallKeep allocWithZone: nil]; + [callKeep setup:options]; +} + RCT_EXPORT_METHOD(setup:(NSDictionary *)options) { + if (_isSetup) { +#ifdef DEBUG + NSLog(@"[RNCallKeep][setup] already setup"); +#endif + return; + } + #ifdef DEBUG NSLog(@"[RNCallKeep][setup] options = %@", options); #endif @@ -149,6 +164,8 @@ + (void)initCallKitProvider { self.callKeepProvider = sharedProvider; [self.callKeepProvider setDelegate:self queue:nil]; + + _isSetup = YES; } RCT_REMAP_METHOD(checkIfBusy, @@ -183,7 +200,7 @@ + (void)initCallKitProvider { supportsHolding:(BOOL)supportsHolding supportsDTMF:(BOOL)supportsDTMF supportsGrouping:(BOOL)supportsGrouping - supportsUngrouping:(BOOL)supportsUngrouping) + supportsUngrouping:(BOOL)supportsUngrouping) { [RNCallKeep reportNewIncomingCall: uuidString handle: handle diff --git a/package.json b/package.json index 1a3fbfda..ca4c09d0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-callkeep", - "version": "4.1.0", + "version": "4.1.1-iosfix", "description": "iOS 10 CallKit and Android ConnectionService Framework For React Native", "main": "index.js", "scripts": {}, From 479046ccbe2230433ab2017f1d728a44f2c9f1c2 Mon Sep 17 00:00:00 2001 From: Jonas Swiatek Date: Mon, 5 Apr 2021 18:02:37 +0200 Subject: [PATCH 2/4] Adjusted if-statement in init so it doesn't touch the _isStartCallActionEventListenerAdded variable --- ios/RNCallKeep/RNCallKeep.m | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/ios/RNCallKeep/RNCallKeep.m b/ios/RNCallKeep/RNCallKeep.m index 0c891a98..0c3858bc 100644 --- a/ios/RNCallKeep/RNCallKeep.m +++ b/ios/RNCallKeep/RNCallKeep.m @@ -55,10 +55,8 @@ - (instancetype)init NSLog(@"[RNCallKeep][init]"); #endif if (self = [super init]) { - if (_delayedEvents == nil) { - _isStartCallActionEventListenerAdded = NO; - _delayedEvents = [NSMutableArray array]; - } + _isStartCallActionEventListenerAdded = NO; + if (_delayedEvents == nil) _delayedEvents = [NSMutableArray array]; } return self; } @@ -122,9 +120,10 @@ - (void)sendEventWithNameWrapper:(NSString *)name body:(id)body { [self sendEventWithName:name body:body]; } else { NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys: - name, @"name", - body, @"data", - nil]; + name, @"name", + body, @"data", + nil + ]; [_delayedEvents addObject:dictionary]; } } From 4690abcbbaaf9932f079454cba587d756259fa44 Mon Sep 17 00:00:00 2001 From: Jonas Swiatek Date: Tue, 6 Apr 2021 10:31:06 +0200 Subject: [PATCH 3/4] Reverted changes to packages.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ca4c09d0..1a3fbfda 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-callkeep", - "version": "4.1.1-iosfix", + "version": "4.1.0", "description": "iOS 10 CallKit and Android ConnectionService Framework For React Native", "main": "index.js", "scripts": {}, From e5607f50e3e60e96ecbc3885dca978b435fd8de3 Mon Sep 17 00:00:00 2001 From: Jonas Swiatek Date: Fri, 9 Apr 2021 13:58:40 +0200 Subject: [PATCH 4/4] Added documentation and change code so subsequent calls to setup will only be ignored if initial setup was done in AppDelegate.m --- README.md | 32 +++++++++++++++++++++++++++++++- ios/RNCallKeep/RNCallKeep.m | 9 +++++---- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 264d5077..f49ffff8 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,34 @@ const options = { RNCallKeep.setup(options).then(accepted => {}); ``` +iOS only. + +Alternative on iOS you can perform setup in `AppDelegate.m`. Doing this allows capturing events prior to the react native event bridge being up. Please be aware that calling setup in `AppDelegate.m` will ignore any subsequent calls to `RNCallKeep.setup();`. + +```objective-c +@implementation AppDelegate +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions +{ + self.bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions]; + + [RNCallKeep setup:@{ + @"appName": @"Awesome App", + @"maximumCallGroups": @3, + @"maximumCallsPerCallGroup": @1, + @"supportsVideo": @NO, + }]; + + RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:self.bridge + moduleName:@"App" + initialProperties:nil]; + + // ======== OTHER CODE REDACTED ========== + + return YES; +} + +``` + - `options`: Object - `ios`: object - `appName`: string (required) @@ -93,7 +121,7 @@ RNCallKeep.setup(options).then(accepted => {}); - `additionalPermissions`: [PermissionsAndroid] (optional) Any additional permissions you'd like your app to have at first launch. Can be used to simplify permission flows and avoid multiple popups to the user at different times. - + `setup` calls internally `registerPhoneAccount` and `registerEvents`. ## Constants @@ -641,6 +669,8 @@ Called as soon as JS context initializes if there were some actions performed by Since iOS 13, you must display incoming call on receiving PushKit push notification. But if app was killed, it takes some time to create JS context. If user answers the call (or ends it) before JS context has been initialized, user actions will be passed as events array of this event. Similar situation can happen if user would like to start a call from Recents or similar iOS app, assuming that your app was in killed state. +In order for this event to reliably fire, it's necessary to perform setup in `AppDelegate.m` + **NOTE: You still need to subscribe / handle the rest events as usuall. This is just a helper whcih cache and propagate early fired events if and only if for "the native events which DID fire BEFORE js bridge is initialed", it does NOT mean this will have events each time when the app reopened.** ```js diff --git a/ios/RNCallKeep/RNCallKeep.m b/ios/RNCallKeep/RNCallKeep.m index 0c3858bc..b87139b9 100644 --- a/ios/RNCallKeep/RNCallKeep.m +++ b/ios/RNCallKeep/RNCallKeep.m @@ -12,6 +12,7 @@ #import #import #import +#import #import @@ -41,9 +42,9 @@ @implementation RNCallKeep BOOL _isStartCallActionEventListenerAdded; bool _hasListeners; NSMutableArray *_delayedEvents; - bool _isSetup; } +static bool isSetupNatively; static CXProvider* sharedProvider; // should initialise in AppDelegate.m @@ -138,13 +139,15 @@ + (void)initCallKitProvider { + (void)setup:(NSDictionary *)options { RNCallKeep *callKeep = [RNCallKeep allocWithZone: nil]; [callKeep setup:options]; + isSetupNatively = YES; } RCT_EXPORT_METHOD(setup:(NSDictionary *)options) { - if (_isSetup) { + if (isSetupNatively) { #ifdef DEBUG NSLog(@"[RNCallKeep][setup] already setup"); + RCTLog(@"[RNCallKeep][setup] already setup in native code"); #endif return; } @@ -163,8 +166,6 @@ + (void)setup:(NSDictionary *)options { self.callKeepProvider = sharedProvider; [self.callKeepProvider setDelegate:self queue:nil]; - - _isSetup = YES; } RCT_REMAP_METHOD(checkIfBusy,