Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions ios/RNCallKeep/RNCallKeep.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,6 @@ continueUserActivity:(NSUserActivity *)userActivity

+ (BOOL)isCallActive:(NSString *)uuidString;

+ (void)setup:(NSDictionary *)options;

@jonastelzio jonastelzio Apr 5, 2021

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Expose a static method to call setup from AppDelegate.m

@end
29 changes: 23 additions & 6 deletions ios/RNCallKeep/RNCallKeep.m
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#import <React/RCTConvert.h>
#import <React/RCTEventDispatcher.h>
#import <React/RCTUtils.h>
#import <React/RCTLog.h>

#import <AVFoundation/AVAudioSession.h>

Expand Down Expand Up @@ -43,6 +44,7 @@ @implementation RNCallKeep
NSMutableArray *_delayedEvents;
}

static bool isSetupNatively;
static CXProvider* sharedProvider;

// should initialise in AppDelegate.m
Expand All @@ -55,7 +57,7 @@ - (instancetype)init
#endif
if (self = [super init]) {
_isStartCallActionEventListenerAdded = NO;
_delayedEvents = [NSMutableArray array];
if (_delayedEvents == nil) _delayedEvents = [NSMutableArray array];

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

init is called repeatedly, deleting any events queued up here. This avoids that.

}
return self;
}
Expand Down Expand Up @@ -118,10 +120,11 @@ - (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
];

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

body can be null for certain events, such as RNCallKeepDidActivateAudioSession which will fire before the bridge is up if answering a call really quickly!

[_delayedEvents addObject:dictionary];
}
}
Expand All @@ -133,8 +136,22 @@ + (void)initCallKitProvider {
}
}

+ (void)setup:(NSDictionary *)options {
RNCallKeep *callKeep = [RNCallKeep allocWithZone: nil];
[callKeep setup:options];
isSetupNatively = YES;
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simply allocate the singleton and call setup in there, setting isSetupNatively makes the library ignore further calls to setup from react native.


RCT_EXPORT_METHOD(setup:(NSDictionary *)options)
{
if (isSetupNatively) {
#ifdef DEBUG
NSLog(@"[RNCallKeep][setup] already setup");
RCTLog(@"[RNCallKeep][setup] already setup in native code");
#endif
return;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we've already initialized from AppDelegate.m, we ignore further calls to setup from React Native.

}

Comment thread
jonastelzio marked this conversation as resolved.
#ifdef DEBUG
NSLog(@"[RNCallKeep][setup] options = %@", options);
#endif
Expand Down Expand Up @@ -183,7 +200,7 @@ + (void)initCallKitProvider {
supportsHolding:(BOOL)supportsHolding
supportsDTMF:(BOOL)supportsDTMF
supportsGrouping:(BOOL)supportsGrouping
supportsUngrouping:(BOOL)supportsUngrouping)
supportsUngrouping:(BOOL)supportsUngrouping)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whatever was sitting at the end of this line, xcode insists on deleting it when I save the file 🤷‍♂️

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

whitespace is the devil

{
[RNCallKeep reportNewIncomingCall: uuidString
handle: handle
Expand Down