iOS Callkit: CXProvider resets immediately after starting
Asked Answered
S

5

6

I am converting an existing VoIP application to Callkit. I have a lot of code in place but somehow when I initialize the CXProvider it will call providerDidBegin and immediately after that it will call providerDidReset. It doesn't give a reason for that. I cannot register one of my outgoing phone calls after that because my provider isn't active.

I have tried looking into certificates, settings and so on but basically I don't need more than I already have for my VoIP app it seems.

The call from CallKit calling the reset method is the following:

CallKit`__42-[CXProvider handleConnectionInterruption]_block_invoke:

When I dig deeper where it comes from, it's NSXPCConnection related. What is this connection and how do I need to set it up?

Of course there is no interruption in the connection.

This is how I initialize my Delegate:

- (id)init {
    self = [super init];

    self.configuration = [[ProviderConfiguration alloc] init];
    self.provider = [[CXProvider alloc] initWithConfiguration:self.configuration];

    [self.provider setDelegate:self queue:dispatch_get_main_queue()];

    return self;
}

This is what the configuration looks like:

- (instancetype)init {
    self = [super initWithLocalizedName:@"MyCompany"];

    self.supportsVideo = NO;
    self.maximumCallsPerCallGroup = 1;
    self.supportedHandleTypes = [[NSSet alloc] initWithObjects:[NSNumber numberWithInt:(int)CXHandleTypePhoneNumber], nil];
    self.maximumCallGroups = 1;
    self.maximumCallsPerCallGroup = 5;


    return self;
}

Both callbacks are implemented:

- (void)providerDidBegin:(CXProvider *)provider {
    NSLog(@"Begun");
}

- (void)providerDidReset:(CXProvider *)provider {
    NSLog(@"Reset");
}
Stockyard answered 19/4, 2017 at 18:48 Comment(0)
C
16

In my case the same issue was due to missing VOIP background mode in Info.plist file

<key>UIBackgroundModes</key>
<array>
    <string>audio</string>
    <string>voip</string>
</array>

XCode 9 doesn't allow to set this background mode using the Capabilities tab for some unknown reason.

Cari answered 4/10, 2017 at 16:43 Comment(1)
Since most people seem to be helped by your answer I'll set it to the accepted answerStockyard
L
2

Make sure you're calling reportNewIncomingCallWithUUID:update:completion with a valid, nonnull, UUID. Apple's current implementation calls completion with no error but no call screen is shown

Loralyn answered 1/2, 2018 at 22:29 Comment(1)
I bet internally something got reset to nil during the lifetime of the object as inlining the code helped in this case.Stockyard
S
1

Somehow these lines were the problem:

self.configuration = [[ProviderConfiguration alloc] init];
self.provider = [[CXProvider alloc] initWithConfiguration:self.configuration];

It got stored in self.configuration before calling init. By putting the same code there inline it worked.

CXProviderConfiguration *configuration = [[CXProviderConfiguration alloc] initWithLocalizedName:@"MyCompany"];

configuration.supportsVideo = NO;
configuration.supportedHandleTypes = [[NSSet alloc] initWithObjects:[NSNumber numberWithInt:(int)CXHandleTypePhoneNumber], nil];
configuration.maximumCallGroups = 1;
configuration.maximumCallsPerCallGroup = 5;
self.provider = [[CXProvider alloc] initWithConfiguration:configuration];
Stockyard answered 26/4, 2017 at 20:46 Comment(1)
For the benefit of others that may come across this: the problem is that, although CXProviderConfiguration is mutable, CXProvider doesn't actually read any changes to it after initialization (or so it seems). We ran into this when we wanted to change the ring tone dynamically; the solution was to create a new configuration and provider, on the fly (which works fine). Unfortunately, most of the CallKit docs are still just stubs and don't point out these dark corners (nor much else!)Scandinavia
F
0

I've got the same behavior on a simulator. On a device it was OK.

Fantasy answered 13/4, 2020 at 15:49 Comment(0)
R
0

You cannot use providerDidBegin to handle calls because it is used to identify the beginning of your class instance ProviderDelegate or the instance of CXProviderDelegate. To do the correct management you must create auxiliary classes that can do this for you.

See the example below from WWDC 2016: https://github.com/Lax/Learn-iOS-Swift-by-Examples/tree/master/Speakerbox

Ryon answered 31/8, 2020 at 14:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.