如何在iOS默认「通话」弹窗的呼叫/取消操作中获取回调或通知?
获取iOS通话弹窗的用户操作回调
你遇到的这个问题其实是UIApplication.open(_:options:completionHandler:)的设计逻辑导致的——tel://链接是由系统接管的,completionHandler只会在系统成功弹出通话确认弹窗时立刻返回true,它完全不会等待用户点击「呼叫」或「取消」的操作,所以这个回调根本没法用来捕获用户的选择。
要拿到用户在通话弹窗的操作结果,你需要借助CallKit框架中的CXCallObserver,它能监听系统内所有通话的状态变化,包括你通过tel://发起的呼叫。
具体实现步骤
- 首先导入CallKit框架:
import CallKit
- 在你的视图控制器(或合适的类)中创建
CXCallObserver实例,并设置代理:
class YourCallHandlerViewController: UIViewController { // 声明通话观察者 private let callObserver = CXCallObserver() override func viewDidLoad() { super.viewDidLoad() // 设置代理,指定在主队列处理回调(方便更新UI) callObserver.setDelegate(self, queue: DispatchQueue.main) } // 发起呼叫的方法 func initiateCall(to phoneNumber: String) { guard let callURL = URL(string: "tel://\(phoneNumber)") else { print("无效的电话号码") return } // 直接打开tel链接,不需要completionHandler了 UIApplication.shared.open(callURL) } }
- 实现
CXCallObserverDelegate代理方法,监听通话状态变化:
extension YourCallHandlerViewController: CXCallObserverDelegate { func callObserver(_ callObserver: CXCallObserver, callChanged call: CXCall) { // 先判断是不是当前App发起的呼出通话 guard call.isOutgoing else { return } // 用户点击了「呼叫」且通话已连接 if call.hasConnected { print("用户确认呼叫,通话已接通") // 这里可以处理呼叫成功的业务逻辑,比如记录通话日志 } // 用户取消了呼叫,或者通话结束 if call.hasEnded { // 可以结合call.hasConnected来区分:如果hasConnected为false,说明用户取消了呼叫 let didCancel = !call.hasConnected if didCancel { print("用户取消了呼叫") // 处理取消呼叫的逻辑 } else { print("通话正常结束") } } } }
关键说明
CXCallObserver不需要额外的权限配置,只要导入CallKit框架就能使用。- 代理方法会监听系统中所有通话的变化,所以一定要用
call.isOutgoing过滤掉非当前App发起的通话,避免无关的回调干扰。 - 状态区分逻辑:
- 用户点击「取消」:通话不会进入
hasConnected状态,直接触发hasEnded。 - 用户点击「呼叫」:会先进入连接中状态,然后触发
hasConnected,通话结束时触发hasEnded。
- 用户点击「取消」:通话不会进入
内容的提问来源于stack exchange,提问作者Nermin Sehic




