Affinché un'applicazione iOS di fonia (come WhatsApp, Skype o **Africall**) possa squillare ed essere risposta a schermo bloccato con la medesima schermata verde/rossa delle chiamate telefoniche di sistema, è indispensabile utilizzare l'accoppiata di framework Apple PushKit e CallKit.
1. Registrazione del PushKit VoIP Token
PushKit fornisce un tipo di notifica push ad altissima priorità che risveglia l'app dallo stato di sospensione o kill. A differenza delle notifiche push standard (APNs), una notifica PushKit **deve obbligatoriamente notificare CallKit** entro pochi millisecondi per evitare sanzioni da parte del sistema operativo:
import Foundation
import PushKit
import CallKit
class VoIPPushManager: NSObject, PKPushRegistryDelegate {
static let shared = VoIPPushManager()
private var voipRegistry: PKPushRegistry?
func registerForVoIPPushNotifications() {
voipRegistry = PKPushRegistry(queue: DispatchQueue.main)
voipRegistry?.delegate = self
voipRegistry?.desiredPushTypes = [.voIP]
}
// Ricezione token PushKit da Apple
func pushRegistry(_ registry: PKPushRegistry, didUpdate pushCredentials: PKPushCredentials, for type: PKPushType) {
let token = pushCredentials.token.map { String(format: "%02.2hhx", $0) }.joined()
print("Token PushKit VoIP generato: \(token)")
}
// Ricezione notifica VoIP in background
func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
guard let callerName = payload.dictionaryPayload["callerName"] as? String,
let callUUIDString = payload.dictionaryPayload["callUUID"] as? String,
let callUUID = UUID(uuidString: callUUIDString) else {
completion()
return
}
// Segnala IMMEDIATAMENTE la chiamata in arrivo a CallKit
CallKitManager.shared.reportIncomingCall(uuid: callUUID, handle: callerName) {
completion()
}
}
}
2. Configurazione di CXProvider e Controller CallKit in Swift
CXProvider è l'oggetto responsabile della comunicazione con l'interfaccia telefonica nativa dell'iPhone:
import CallKit
import AVFoundation
class CallKitManager: NSObject, CXProviderDelegate {
static let shared = CallKitManager()
private var provider: CXProvider?
private var callController = CXCallController()
override init() {
super.init()
let config = CXProviderConfiguration(localizedName: "AfriCall VoIP")
config.supportsVideo = false
config.maximumCallGroups = 1
config.supportedHandleTypes = [.phoneNumber]
provider = CXProvider(configuration: config)
provider?.setDelegate(self, queue: nil)
}
func reportIncomingCall(uuid: UUID, handle: String, completion: @escaping () -> Void) {
let update = CXCallUpdate()
update.remoteHandle = CXHandle(type: .phoneNumber, value: handle)
update.hasVideo = false
provider?.reportNewIncomingCall(with: uuid, update: update) { error in
if error == nil {
print("Chiamata nativa iOS notificata a schermo bloccato!")
}
completion()
}
}
// Delegate Methods
func providerDidReset(_ provider: CXProvider) {}
func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
// L'utente ha premuto il tasto verde di risposta nativo
action.fulfill()
}
func provider(_ provider: CXProvider, perform action: CXEndCallAction) {
// L'utente ha agganciato la chiamata
action.fulfill()
}
}
Conclusione
L'integrazione di CallKit e PushKit garantisce un'esperienza utente nativa per chiamate VoIP di livello professionale. Per integrare CallKit nelle tue applicazioni iOS, scrivi a diallooyunus@gmail.com.