Search code examples
iosswiftcallkitpushkit

Is there a way to discard a VoIP push notification call request?


I'm implementing an intercom feature, which by specs should report and allow one call only, ignoring any call request if there's one already reported or answered (in progress).

The simplest thing to do is to ignore the VoIP push notification message of subsequent calls, but that is disallowed by Apple, because if a notification is not followed by a call to CXProvider's reportIncomingCall(with:update:completion), the app is terminated (I guess this is to prevent using these notifications for other purposes, questionable choice...).

So, even if a call must be discarded, the push notification handler must still call that method. I tried calling reportIncomingCall(), followed up by an end of call request, using either:

self.provider.reportNewIncomingCall(with: uuid, update: update) { error in
  self.provider.reportCall(with: uuid, endedAt: Date(), reason: .answeredElsewhere)
}

and

self.provider.reportNewIncomingCall(with: uuid, update: update) { error in
  let endCallAction = CXEndCallAction(call: uuid)
  let transaction = CXTransaction(action: endCallAction)
  self.controller.request(transaction) { error in
  }  
}

(note that this is not the actual code I'm using, as the architecture is a bit more elaborated in the project)

where controller is an instance of CXCallController. I also tried with a combination of both, but the 2nd call is still reported and I have to manually end it.

Is there a "legal" way to discard a VoIP call request? I haven't found anything in the documentation, just the rule that each VoIP push notification must be followed by a call to reportIncomingCall().


Solution

  • It turns out I made a mistake in my code - I was passing the wrong identifier to reportCall(with:endedAt:reason:), so it was not ending the call that was just reported. So this code works fine:

    self.provider.reportNewIncomingCall(with: uuid, update: update) { error in
      self.provider.reportCall(with: uuid, endedAt: Date(), reason: .answeredElsewhere)
    }
    

    It makes Apple happy :-)., and no UI about that canceled call is shown to the user.

    Be sure to also read @Marco's answer. That would definitely be a good way to decline calls (by just ignoring the notification), but since it's not explicitly mentioned in the documentation, I don't want to find out in the future that Apple has changed the way it works.