I have implemented VOIP calls in my application and I am trying to show a screen when the user answers a call.
VoipNotificationManager.swift
// Handle incoming pushes
func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
let callManager = CallManager()
let id = UUID()
callManager.reportIncomingCall(id: id, handle: "Assistant")
}
CallManager.swift
// MARK: Incoming calls
func reportIncomingCall(id: UUID, handle: String) {
let update = CXCallUpdate()
update.remoteHandle = CXHandle(type: .generic, value: handle)
update.hasVideo = true
provider.reportNewIncomingCall(with: id, update: update) { error in
if let error = error?.localizedDescription {
print("Report incoming call error: \(error)")
} else {
print("Call reported")
}
}
}
// Runs the user answers a call
func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
print("Call answered")
action.fulfill()
// Show view
}
When I run the PHP script (check last code snippet for the PHP code), I receive a call but when I answer the call, the CXAnswerCallAction
function doesn't run.
But the CXAnswerCallAction
function runs when I run the app and click on a button which replicates an incoming call like so (this method doesn't involve a PHP script):
// Call button
Button {
let callManager = CallManager()
let id = UUID()
callManager.reportIncomingCall(id: id, handle: "Assistant")
} label: {
Text("Call")
}
Also, here's the PHP code I run to receive a call:
if ( defined("CURL_VERSION_HTTP2") && (curl_version()["features"] & CURL_VERSION_HTTP2) !== 0) {
$ch = curl_init();
$body ['aps'] = array (
"alert" => array (
"status" => 1,
"title" => "Assistant",
"body" => "Incoming Video Call",
),
"badge" => 1,
"sound" => "default",
"voip" => true
);
$curlconfig = array(
CURLOPT_URL => "https://api.development.push.apple.com/3/device/token",
CURLOPT_RETURNTRANSFER =>true,
CURLOPT_POSTFIELDS => json_encode($body),
CURLOPT_SSLCERT =>"App.pem",
CURLOPT_SSLCERTPASSWD => "Pass",
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_2_0,
CURLOPT_VERBOSE => true
);
curl_setopt_array($ch, $curlconfig);
$res = curl_exec($ch);
if ($res === FALSE) {
echo('Curl failed: ' . curl_error($ch));
}
curl_close($ch);
} else {
echo "No HTTP/2 support on client.";
}
I don't think there are any issues with the script as it runs with no issue and when I run it, the device receives a call.
Looks like your CallManager
will be getting released as soon as pushRegistry
returns (since it's initialised as a local variable inside pushRegistry
) so by the time the call is answered there will be no CXProviderDelegate
.
You should initialise one instance of CallManager
early in your app lifecycle and use this instance throughout the app.
For example, you might make CallManager
a singleton and use CallManager.shared
in your VoipNotificationManager.swift
and elsewhere:
class CallManager: CXProviderDelegate {
static let shared = CallManager()
// private init to prevent other instances
private init() {
// probably create CXProvider and set CXProviderDelegate here
}
...