Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Table of Contents

Пример iOS приложения для приема входящих звонков с использованием Call Kit

Данный пример может использоваться как основа для написания собственного приложения, использующего Call Kit и пуш-уведомлений для соединения с сервером и приема входящего SIP звонка.

...

При входящем звонке приложение получает пуш-уведомление, даже если оно свернуто или закрыто. Если приложение закрыто, оно подключается к SIP-сессии на сервере с токеном, полученным в уведомлении, и принимает входящий звонок.

Работа с кодом примера

Для разбора кода возьмем версию примера CallKitDemo Swift, которая доступна для скачивания на GitHub

Классы приложения:

  • класс основного вида приложения CallKitDemoViewController (файл CallKitDemoViewController.swift)
  • класс реализации протокола CXProviderDelegate (файл ProviderDelegate.swift)
  • класс для работы с интерфейсом пользователя и реестром пуш-уведомлений AppDelegate (файл AppDelegate.swift)
  • расширение для создания объекта CXAnswerCallAction по действию пользователя, для ответа на звонок NSUserActivity: StartCallConvertible (файл NSUserActivity+StartCallConvertible.swift)
  • расширение для создания объекта CXAnswerCallAction из URL, для ответа на звонок URL: StartCallConvertible (файл URL+StartCallConvertible.swift)
  • расширение для создания звонка, реализующее протокол INStartCallIntentHandling (файл CallKitIntentExtension/IntentHandler.swift)

1. Импорт API

code

Code Block
languagejs
themeRDark
import FPWCSApi2Swift

2. Подключение к серверу и создание SIP-сессии

FPWCSApi2.createSession code

При создании сессии передаются следующие параметры:

  • urlServer - URL  WCS сервера
  • keepAlive - сохранять сессию при отключении клиента
  • sipRegisterRequired - регистрировать сессию на SIP сервере
  • sipLogin - имя пользователя на SIP сервере
  • sipAuthenticationName - имя пользователя для аутентификации на SIP сервере
  • sipPassword - пароль на SIP сервере
  • sipDomain - адрес SIP сервера
  • sipOutboundProxy - адрес SIP сервера
  • sipPort - порт на SIP сервере
  • noticationToken - токен для получения уведомлений о входящих звонках
  • appId - идентификатор приложения
  • appKey - REST hook  приложение на WCS сервере
Code Block
languagejs
themeRDark
            let options = FPWCSApi2SessionOptions()
            options.urlServer = wcsUrl.text
            
            options.keepAlive = true
            
            options.sipRegisterRequired = true
            options.sipLogin = sipLogin.text
            options.sipAuthenticationName = sipAuthName.text
            options.sipPassword = sipPassword.text
            options.sipDomain = sipDomain.text
            options.sipOutboundProxy = sipOutboundProxy.text
            options.sipPort = Int(sipPort.text ?? "5060") as NSNumber?
            
            let userDefaults = UserDefaults.standard
            options.noticationToken = userDefaults.string(forKey: "voipToken")
            options.appId = "com.flashphoner.ios.CallKitDemoSwift"

            options.appKey = "defaultApp"

            do {
                let session = try FPWCSApi2.createSession(options)

                processSession(session)

                appDelegate.providerDelegate?.setSession(session)
                session.connect()
            } catch {
                print(error)
            }

...

Code Block
languagejs
themeRDark
    func setSession(_ session: FPWCSApi2Session) {
        self.session = session;
        
        
        session.onIncomingCallCallback({ rCall in
            
            guard let call = rCall else {
                return
            }
                        
            call.on(kFPWCSCallStatus.fpwcsCallStatusFinish, callback: {rCall in
                self.viewController.toNoCallState()

                guard let uuid = rCall?.getUuid() else {
                    return
                }
                self.provider.reportCall(with: uuid, endedAt: Date(), reason: .remoteEnded)
            })
            let id = call.getId()
            
            NSLog("CKD - session.onIncomingCallCallback. wcsCallId: " + (id ?? ""))

            
            call.on(kFPWCSCallStatus.fpwcsCallStatusEstablished, callback: {rCall in
                self.viewController.toHangupState(call.getId())
            })
            
            self.viewController.toAnswerState(call.getId())
            self.currentCall = call
            self.actionCall?.fulfill()
        })
    }

5. Запрос действия для ответа на звонок

code

Code Block
languagejs
themeRDark
    func answer(_ callId: String) {
        guard let call = self.session?.getCall(callId) else {
            return
        }
        let callController = CXCallController()
        let answerCallAction = CXAnswerCallAction(call: call.getUuid())
        callController.request(CXTransaction(action: answerCallAction),
                                             completion: { error in
                                                 if let error = error {
                                                     print("Error: \(error)")
                                                 } else {
                                                     print("Success")
                                                 }
                                             })
    }

...