iOS Callkit - incoming Call Recents History

5.1k views Asked by At

I've implemented call kit in our app only for received incoming call when the app is close or on background (push call notification). I just noticed that every time I received a call and use callkit to display it, this call automatically appear in the call history (Recents tab in native Call App).

Every time I click on one of those recent, my App is resume or launch. I wanted to make the app place an outgoing call after the user press the recent call but I didn't find anything about it.

  • Is there a way to detect that the app was opened / resumed from this call recent click ?
  • Can we disable this callkit feature ?

Thanks for providing information :)

2

There are 2 answers

4
user102008 On BEST ANSWER

I wanted to make the app place an outgoing call after the user press the recent call but I didn't find anything about it.

In your app's Info.plist, you must have INStartAudioCallIntent and/or INStartVideoCallIntent in the NSUserActivityTypes key, and your app delegate must implement the -application:continueUserActivity:restorationHandler: method to handle the start call intent. See the Speakerbox example app for details.

Can we disable this callkit feature ?

If you don't set a remoteHandle for the call's CXCallUpdate, the item in Recents won't be pressable.

3
Bilal Şimşek On

for future reference;

  1. call kit provider configuration should have this list of generic and phone number types

    config.supportedHandleTypes = [.generic,.phoneNumber]
    
  2. Callkit update remotehandle should be initialized like below

     update.remoteHandle = CXHandle(type: .generic, value:String(describing: payload.dictionaryPayload["caller_id"]!))
    

3.You should add Intents.framework to your project by selecting project>target>Build Phases> Link Binary With Libraries and click + button

  1. You should add INStartCallIntent to your info.plist like below

    <key> NSUserActivityTypes </key>
         <array>
             <string>INStartCallIntent</string>
         </array>
    
  2. for swift 5 you should add below function to your SceneDelegate.swift

    func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {}
    

or for swift 4 and below you should add below function to Appdelegate.swift

func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {

 return true
}

then add code below to your continue useractivity function

let interaction = userActivity.interaction
            if let startAudioCallIntent = interaction?.intent as? INStartAudioCallIntent{
        
                let contact = startAudioCallIntent.contacts?.first
            
                let contactHandle = contact?.personHandle
    
                    if let phoneNumber = contactHandle?.value {
                       print(phoneNumber)
                      // Your Call Logic
                        }
                    }
         
            }

  

you should get a warning that

 INStartAudioCallIntent' was deprecated in iOS 13.0: INStartAudioCallIntent is deprecated. Please adopt INStartCallIntent instead

applying this suggestion fails because startAudioCallIntent cant be cast to INStartCallIntent so ignore it.

VERY IMPORTANT continue useractivity function in scene delegate is not called whan app is terminated so to run your intent when app is start you should add code block to

 func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {}

and your code should be like below

 func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
     
        let contentView = ContentView()

        // Use a UIHostingController as window root view controller.
        if let windowScene = scene as? UIWindowScene {
            let window = UIWindow(windowScene: windowScene)
            window.rootViewController = UIHostingController(rootView: contentView.environmentObject(AppDelegate.shared)) // This is my code so you may not use Appadelegate.shared. ignore it
            self.window = window
            window.makeKeyAndVisible()
        }
        
        
        if let userActivity = connectionOptions.userActivities.first {
            let interaction = userActivity.interaction
            if let startAudioCallIntent = interaction?.intent as? INStartAudioCallIntent{
        
                let contact = startAudioCallIntent.contacts?.first
            
                let contactHandle = contact?.personHandle

                    if let phoneNumber = contactHandle?.value {
                        
                        // Your Call Logic
                    }
         
            }
          }
        
    }