How can I find out whether the user pressed the Call or the Cancel button when making a call from my app?
Here is an iOS 10+ solution for Swift 4.2, tested with iOS 12 that detects both the Cancel and the Call button.
Don't forget to import CallKit and conform your class to CXCallObserverDelegate
!
let callObserver = CXCallObserver()
var didDetectOutgoingCall = false
func showCallAlert() {
guard let url = URL(string: "tel:+36201234567"),
UIApplication.shared.canOpenURL(url) else {
return
}
callObserver.setDelegate(self, queue: nil)
didDetectOutgoingCall = false
//we only want to add the observer after the alert is displayed,
//that's why we're using asyncAfter(deadline:)
UIApplication.shared.open(url, options: [:]) { [weak self] success in
if success {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
self?.addNotifObserver()
}
}
}
}
func addNotifObserver() {
let selector = #selector(appDidBecomeActive)
let notifName = UIApplication.didBecomeActiveNotification
NotificationCenter.default.addObserver(self, selector: selector, name: notifName, object: nil)
}
@objc func appDidBecomeActive() {
//if callObserver(_:callChanged:) doesn't get called after a certain time,
//the call dialog was not shown - so the Cancel button was pressed
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { [weak self] in
if !(self?.didDetectOutgoingCall ?? true) {
print("Cancel button pressed")
}
}
}
func callObserver(_ callObserver: CXCallObserver, callChanged call: CXCall) {
if call.isOutgoing && !didDetectOutgoingCall {
didDetectOutgoingCall = true
print("Call button pressed")
}
}
This isn't perfect, but you could identify that "call" was pressed instead of "cancel" by listening for the UIApplicationSuspendedNotification (you'd have to add some logic to ignore this event when someone pushed the 'home' key, or was accepting an incoming call... maybe by adding/removing the observer around the logic where the phone number is being presented):
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(suspended:) name:@"UIApplicationSuspendedNotification" object:nil];
-(void)suspended:(NSNotification *) notification
{
NSLog(@"Suspended");
}
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(suspended:) name:@"UIApplicationSuspendedNotification" object:nil];
The above code by @J Saprio works absolutely fine. Before it suspends the Application NSNotificationCenter
call UIApplicationSuspendedNotification
. Once you click the "call" it will execute the (suspended:)
method. Here the catch is, every time you call NSNotificationCenter
method it will give a call to (suspended:)
with the increment of one. Solution is to remove the observer for NSNotificationCenter
. Following is the snippet for it. It will help you to execute the following method only once.
-(void)suspended:(NSNotification *) notification
{
NSLog(@"Suspended");
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"UIApplicationSuspendedNotification" object:nil];
}