Intercom & PushKit

Intercom integration

In order to integrate VoIP push messages into your application, you need to make the following changes.

Capabilities

Go to your project -> your target -> Signing & Capabilities -> + Capability.

Add Background Modes.

And Push Notifications.

Further it is necessary to mark the following points: Audio, Voice over IP, and Remote notifications.

Frameworks

You need to link CallKit and PushKit frameworks.

Code

In order to register VoIP device token on the backend, you need to pass it to SmartSpacesKit (starting from version 0.4.0).


import UIKit
import PushKit
import SmartSpacesKit

@UIApplicationMain
class AppDelegate: UIResponder {

...

}

extension AppDelegate: UIApplicationDelegate {

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        ...

        SWSmartLockManager.shared().intercomManager.delegate = self

        registerVoIP()

        return true
    }

}

extension AppDelegate {

    func registerVoIP() {
        let voipRegistry = PKPushRegistry(queue: .main)
        voipRegistry.delegate = self
        voipRegistry.desiredPushTypes = [.voIP]
    }

    func open(intercomDevice: Intercom.Device) {
        SWSmartLockManager.shared().intercomManager.open(doorAssociatedWith: intercomDevice) { error in
            // This callback duplicates didFinishOpening gelegate method
            print("[DEBUG] Intercom manager did finish opening the device: \(intercomDevice) with error: \(String(describing: error))")
        }
    }

}

extension AppDelegate: PKPushRegistryDelegate {

    func pushRegistry(_ registry: PKPushRegistry, didUpdate pushCredentials: PKPushCredentials, for type: PKPushType) {
        guard type == .voIP else {
            return
        }

        UserDeviceManager.shared().update(voipNotificationToken: pushCredentials.token)
        UserDeviceManager.shared().synchronize { error in
            if let error = error { print("[ERROR] Failed to synchronize user device manager: \(error)"); return }
            print("[DEBUG] Synchronizing user device manager finished")
        }
    }

    func pushRegistry(_ registry: PKPushRegistry, didInvalidatePushTokenFor type: PKPushType) {
        guard type == .voIP else {
            return
        }

        UserDeviceManager.shared().update(voipNotificationToken: nil)
        UserDeviceManager.shared().synchronize { error in
            if let error = error { print("[ERROR] Failed to synchronize user device manager: \(error)"); return }
            print("[DEBUG] Synchronizing user device manager finished")
        }
    }

    func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
        defer {
            completion()
        }

        guard
            type == .voIP,
            UserDeviceManager.shared().currentUserDevice != nil,
            let payload = payload.dictionaryPayload as? [String: Any]
        else {
            return
        }

        do {
            try SWSmartLockManager.shared().intercomManager.on(pushNotificationPayload: payload)
        } catch {
            print("[DEBUG] Intercom manager returned an error: \(error)")
        }
    }

}

extension AppDelegate: IntercomManagerDelegate {

    func didFinishOpening(intercomManager: Intercom.Manager, device intercomDevice: Intercom.Device, error: Error?) {
        print("[DEBUG] Intercom manager did finish opening the device: \(intercomDevice) with error: \(String(describing: error))")
    }

    func didReceiveIncomingCall(intercomManager: Intercom.Manager, device intercomDevice: Intercom.Device, completionHandler: @escaping (Intercom.Action, SWIntercomManagerDelegateCompletion?) -> Void) {
        let confirmationController = UIAlertController(title: "Intercom incoming call", message: "Do you want to receive a call?", preferredStyle: .actionSheet)

        let accept = UIAlertAction(title: "Accept", style: .default) { _ in
            completionHandler(.accept) { error in
                // Show the calling UI.
                print("[DEBUG] Accepting the call returned an error: \(String(describing: error))")
            }
        }
        let decline = UIAlertAction(title: "Decline", style: .destructive) { _ in
            completionHandler(.decline) { error in
                print("[DEBUG] Declining the call returned an error: \(String(describing: error))")
            }
        }
        // The ignore action does not require to call the completionHandler.
        let ignore = UIAlertAction(title: "Ignore", style: .cancel) { _ in
            completionHandler(.ignore, nil)
        }

        confirmationController.addAction(accept)
        confirmationController.addAction(decline)
        confirmationController.addAction(ignore)

        window?.rootViewController?.present(confirmationController, animated: true, completion: nil)
    }

    func shouldStopCalling(intercomManager: Intercom.Manager, device intercomDevice: Intercom.Device?) {
        // Dismiss the calling UI.
    }

}