1

From many days I am stuck at this problem...

AnyHashable("aps"): {
    alert =     {
        action = test;
        body = "{\"action\":\"connect\",\"meetingId\":\"mdkdkkydjgedjhd\",\"from\":\"sender\",\"fromToken\":\"9d739e878521cf770d9e5136161cf7611c242ef2a8b53c83c81b6b6021a7b31b\",\"to\":\"receiver\",\"toToken\":\"e65bf5e3d6a3e440eb364fb620539de4f4c2c1bf98be5f753f5abfbe7fecea74\",\"callUUID\":\"9EB823F3-F857-490B-BCFC-373D05E56933\"}";
        title = Call;
    };
}]

This is the payload which I am receiving and raising an incoming call as per the action

func getPushkitPayload(payload : [AnyHashable : Any], completionOfHandlingIncomingCall : @escaping (Bool) -> Void){
    let dict : Dictionary <String, AnyObject> = payload["aps"] as! Dictionary<String, AnyObject>
    let Alert : Dictionary <String, AnyObject> = dict["alert"] as! Dictionary<String, AnyObject>
    let strBody : String = Alert["body"] as? String ?? ""

    if let data = strBody.data(using: String.Encoding.utf8) {
        do {
            let model = try JSONDecoder().decode(PushkitModel.self, from: data)
            print("RES MODEL")
            dump(model)
            //if app background
            if  UIApplication.shared.applicationState == .background || UIApplication.shared.applicationState == .inactive {
                //here check action if it is connect then show incoming call
                if model.action == "connect" {
                    CallKitManager.shared.receiveCall(model: model, delegate: self) { (initiated) in
                        completionOfHandlingIncomingCall(initiated)
                    }
                } else {
                    let sendModelToNotCenter:[String: Model] = ["Model": model]
                    NotificationCenter.default.post(name: Notification.Name("DisconnectCallFromReceiver"), object: nil, userInfo: sendModelToNotCenter)
                }
            } else {
                //here check action if it is connect then show incoming call
                if model.action == "connect" {
                    CallKitManager.shared.receiveCall(model: model, delegate: self) { (initiated) in
                        completionOfHandlingIncomingCall(initiated)
                    }
                } else {
                    let sendModelToNotCenter:[String: Model] = ["Model": model]
                    NotificationCenter.default.post(name: Notification.Name("DisconnectCallFromReceiver"), object: nil, userInfo: sendModelToNotCenter)
                }
            }
        } catch let error as NSError {
            print(error)
        }
    }
}

in CallKitManager.shared.receiveCall(model: model, delegate: self) { (initiated) in completionOfHandlingIncomingCall(initiated) I reported the received uuid to callkit. (by taking ref from here) like

public func receiveCall(model: PushkitModel, delegate : CallKitDelegate, completion : @escaping (Bool) -> ()) {
    self.delegate = delegate
    self.model = model
    receiveCallDetails(delay: 0){ (initiated) in
        completion(initiated)
    }
}

public func receiveCallDetails(delay: TimeInterval, completion : @escaping (Bool) -> ()) {
    if let model = self.model, let uuid = UUID(uuidString: model.callUUID) {
        let update = CXCallUpdate()
        update.remoteHandle = CXHandle(type: .emailAddress, value: model.from)

        let bgTaskID = UIApplication.shared.beginBackgroundTask(expirationHandler: nil)
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + delay) {
            self.provider?.reportNewIncomingCall(with: uuid, update: update, completion: { (error) in
                if error == nil {
                }
                completion(true)
            })
            /* If you didn’t put caller information in your notification’s payload, call the reportCall(with:updated:) method of your app's provider object to update the calling interface. You can call that method at any time to update calls. For example, call it after your app fetches updated caller information from your VoIP server.*/
            // Asynchronously register with the telephony server and
            // process the call. Report updates to CallKit as needed.
            **self.provider?.reportCall(with: uuid, updated: update)**
            UIApplication.shared.endBackgroundTask(bgTaskID)

        }
    }  
}

I can receive payload when app open and incoming call also initiates. But when I close my app on iOS 13, I am getting an error

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Killing app because it never posted an incoming call to the system after receiving a PushKit VoIP push callback.'

As I already reported my call. If anyone having a solution it would be great.

Marco
  • 1,572
  • 1
  • 10
  • 21
ki1234
  • 103
  • 1
  • 10
  • Looking at your code, it seems that you expect to receive a VoIP push with an action that is not "connect" to end your call, is that right? If so, that could be the problem, as in this case you receive a VoIP push and do not report a new incoming call. – pepsy Mar 24 '20 at 17:25

1 Answers1

4

I think that the problem is that you're reporting the call inside a DispatchQueue.main.asyncAfter. Even if you set the delay to 0, your code will run in the next run loop, i.e. not immediately. In this way the pushRegistry(_:didReceiveIncomingPushWith:for:completion:) function will end before your call has been reported and thus the system will complain.

So, try to remove the DispatchQueue.main.asyncAfter.

Marco
  • 1,572
  • 1
  • 10
  • 21