You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在PushKit推送后先执行异步任务再调用reportNewIncomingCall?

问题描述

收到PushKit VoIP推送时,必须立刻调用CXProvider().reportNewIncomingCall,否则应用会被系统强制杀死,报错信息如下:

Killing app because it never posted an incoming call
to the system after receiving a PushKit VoIP push.

想先执行一个异步任务,等任务完成后再调用CXProvider().reportNewIncomingCall,请问有没有可行的实现方式?尝试用后台任务延长执行时间但未成功,代码如下:

var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid

func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
    // Start a background task to extend execution time
    backgroundTaskID = UIApplication.shared.beginBackgroundTask(withName: "HandleVoIPPush") {
        // End task if time expires
        UIApplication.shared.endBackgroundTask(self.backgroundTaskID)
        self.backgroundTaskID = .invalid
    }
    
    // Start your async task
    asyncTask { _ in
        provider.reportNewIncomingCall(with: callUUID, update: update) { _ in }
        
        // End the background task
        UIApplication.shared.endBackgroundTask(self.backgroundTaskID)
        self.backgroundTaskID = .invalid
        
        // Call the completion handler to let the system know you're done
        completion()
    }
}
解决方案

核心限制说明

系统对PushKit VoIP推送的处理有严格时间要求:必须在收到推送后的极短时间内(通常几秒内)调用reportNewIncomingCall,后台任务无法绕过这个限制——因为系统判断的是你是否在推送回调的窗口期内上报来电,而非单纯延长后台运行时间。之前的方案失败,就是因为把上报来电的操作放在了异步任务完成后,超出了系统允许的时间窗口。

可行实现思路

正确的做法是先立刻调用reportNewIncomingCall上报来电,再在后台执行异步任务,具体步骤如下:

  1. 收到PushKit推送后,第一时间生成来电UUID和CXCallUpdate(可先填充基础占位信息,比如来电号码显示"来电中...");
  2. 立刻调用reportNewIncomingCall,触发系统来电UI;
  3. 在reportNewIncomingCall的回调或异步任务中,执行需要的后台操作;
  4. 异步任务完成后,通过CXProvider更新来电详细信息(比如真实号码、来电名称等)。

示例代码

func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
    // 1. 生成必要的来电基础信息
    let callUUID = UUID()
    let update = CXCallUpdate()
    update.remoteHandle = CXHandle(type: .generic, value: "来电中...")
    update.hasVideo = false
    
    // 2. 立刻上报来电,避免被系统杀死
    provider.reportNewIncomingCall(with: callUUID, update: update) { error in
        if let error = error {
            print("上报来电失败: \(error.localizedDescription)")
            completion()
            return
        }
        
        // 3. 上报成功后执行异步任务
        self.asyncTask { result in
            // 4. 异步任务完成后更新来电详细信息
            let updatedUpdate = CXCallUpdate()
            updatedUpdate.remoteHandle = CXHandle(type: .phoneNumber, value: result.realPhoneNumber)
            updatedUpdate.localizedCallerName = result.callerName
            updatedUpdate.hasVideo = result.hasVideo
            
            self.provider.reportCall(with: callUUID, updated: updatedUpdate)
            
            completion()
        }
    }
    
    // 启动后台任务确保异步任务能完成(若任务耗时较长)
    var backgroundTaskID = UIApplication.shared.beginBackgroundTask(withName: "VoIPAsyncTask") {
        UIApplication.shared.endBackgroundTask(backgroundTaskID)
        backgroundTaskID = .invalid
    }
}

关键注意事项

  • 绝对不能推迟reportNewIncomingCall的调用,这是系统硬性规则,违反就会被杀死;
  • 上报来电时的初始信息可用占位符,后续更新后用户会看到真实信息;
  • 异步任务耗时不能过长,后台任务的时间限制通常在30秒左右,超出会被系统终止;
  • 确保CXProvider已正确配置并激活(需在didFinishLaunchingWithOptions中初始化并设置代理)。

内容的提问来源于stack exchange,提问作者Ryan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 01:05:06