
Compartir:
Abdul es desarrollador de Vonage. Ha trabajado en productos de consumo como ingeniero de iOS. En su tiempo libre, le gusta andar en bicicleta, escuchar música y asesorar a aquellos que están comenzando su viaje en la tecnología.
Cómo realizar llamadas salientes con iOS CallKit
Tiempo de lectura: 5 minutos
En este tutorial, crearás una aplicación SwiftUI que pueda realizar llamadas telefónicas utilizando Vonage Client SDK y CallKit. CallKit te permite integrar tu aplicación iOS en el sistema. Al realizar llamadas salientes, el historial de llamadas de tu aplicación estará disponible en la aplicación Teléfono de iOS.
Requisitos previos
Una Account API de Vonage. Si aún no tienes una, puedes inscribirte hoy.
Una Account de Apple Developer y un dispositivo iOS
Xcode 12 y Swift 5 o superior.
Cocoapods para instalar el Client SDK de Vonage para iOS.
Visión general
Primero, implementarás un servidor para manejar la creación de una aplicación de Vonage, usuarios, generación de JWT y webhooks. Luego adaptarás una aplicación iOS que, usando el Vonage Client SDK, realizará llamadas usando CallKit.
Despliegue del servidor
Este proyecto utilizará Mercado de Vonage Cloud Runtime para implementar un servidor Client SDK Voice en la infraestructura de Vonage. Abre el Servidor de muestra de Client SDK Voice de Client SDK Voice. Abre la pestaña "Implementar código" y, si aún no iniciaste sesión, hazlo ahora.
Introduzca un nombre para el despliegue y elija una región. A continuación, haga clic en el botón "Desplegar código".

Para usar Voice API, debes comprar y asignar un número de Vonage a la aplicación. Haz clic en "Asignar un número" para ver tus números existentes o comprar uno nuevo. Una vez hecho esto, haz clic en "Continuar".

Una vez finalizado el despliegue, haz clic en el botón "Iniciar". Esto abrirá la aplicación del servidor en tu navegador, donde podrás leer más sobre cómo funciona el servidor. Para continuar con el tutorial, necesitarás crear un usuario. Los usuarios son la forma en que identificas una aplicación que ejecuta el Vonage Client SDK con las API de Vonage.

Crear un usuario llamado "Alice" y genera un JWT. Los SDK para clientes utilizan JWT para autenticarse con Vonage. Cuando realices una llamada al número de Vonage que asignaste anteriormente a la aplicación, Vonage realizará una solicitud a este servidor que devolverá un objeto de control de llamadas que conectará la llamada entrante con el usuario "Alice".

Descargar el proyecto inicial
Este tutorial se construirá sobre un proyecto existente. Si no estás familiarizado con la realización de llamadas salientes utilizando el Client SDK de Vonage, te recomendamos que sigas el tutorial Cómo hacer llamadas telefónicas con SwiftUI de SwiftUI. Cuando estés listo, puedes clonar el proyecto de inicio desde GitHub utilizando este comando en tu terminal:
git clone git@github.com:Vonage-Community/blog-clientsdk-ios_swift-swiftui_app_to_phone.gitA continuación, cambie el directorio a la carpeta del proyecto e instale la VonageClientSDKVoice dependencia:
cd blog-clientsdk-ios_swift-swiftui_app_to_phone
pod installUna vez completado, puede abrir el proyecto con este comando:
xed . Actualización del proyecto inicial
Dado que va a CallKit para realizar llamadas, puede actualizar la función loginIfNeeded en el archivo ContentView.swift para eliminar el indicador isUsingCallKit bandera. El SDK por defecto este valor a true. Aquí también puedes pegar el JWT para el usuario "Alice" que creaste anteriormente:
func loginIfNeeded() {
guard status != "Connected" else { return }
client.createSession("ey...") { error, sessionId in
if let error {
self.updateStatus(error.localizedDescription)
} else {
self.updateStatus("Connected")
}
}
} Añadir el modo VoIP en segundo plano
CallKit requiere que añadas el modo de fondo VoIP. Asegúrese de que ha iniciado sesión en su Apple developer Account en Xcode a través de las preferencias. Si es así, selecciona tu objetivo y luego elige Firma y capacidades:

A continuación, seleccione el botón de añadir capacidad y la capacidad Modos de fondo. En Modos de fondo, seleccione Voz sobre IP:

Vinculación del marco CallKit
Vincula el framework CallKit a tu proyecto añadiéndolo en Marcos de trabajo, bibliotecas y contenido integrado en General:

Creación del Gestor de Proveedores
Ahora, crearás una clase, ProviderManager. CallKit se encarga de la comunicación entre tu aplicación y el sistema a través de la clase CXProvider. Crea un nuevo archivo Swift (CMD + N) llamado ProviderManager:
import CallKit
import Foundation
import VonageClientSDKVoice
protocol ProviderManagerDelegate: AnyObject {
func callReported(_ providerManager: ProviderManager, callUUID: UUID)
func providerReset()
}
final class ProviderManager: NSObject {
private static var providerConfiguration: CXProviderConfiguration = {
let providerConfiguration = CXProviderConfiguration()
providerConfiguration.maximumCallsPerCallGroup = 1
providerConfiguration.supportedHandleTypes = [.generic, .phoneNumber]
return providerConfiguration
}()
private let provider = CXProvider(configuration: ProviderManager.providerConfiguration)
weak var delegate: ProviderManagerDelegate?
override init() {
super.init()
provider.setDelegate(self, queue: nil)
}
public func reportOutgoingCall(callUUID: UUID) {
provider.reportOutgoingCall(with: callUUID, connectedAt: .now)
}
public func reportFailedCall(callUUID: UUID) {
provider.reportCall(with: callUUID, endedAt: .now, reason: .failed)
}
public func reportEndedCall(callUUID: UUID) {
provider.reportCall(with: callUUID, endedAt: .now, reason: .remoteEnded)
}
}El código anterior incluye la creación de un CXProvider y algunas funciones de ayuda para informar del estado de las llamadas al sistema. La dirección ProviderManagerDelegate también se define aquí.
Aplicación de laCXProviderDelegate
La página CXProviderDelegate le proporciona información actualizada del sistema en relación con las llamadas. Añade una extensión ProviderManager que implemente el delegado en el mismo archivo:
extension ProviderManager: CXProviderDelegate {
func provider(_ provider: CXProvider, perform action: CXStartCallAction) {
provider.reportOutgoingCall(with: action.callUUID, startedConnectingAt: .now)
delegate?.callReported(self, callUUID: action.callUUID)
action.fulfill()
}
func providerDidReset(_ provider: CXProvider) {
delegate?.providerReset()
}
func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) {
VGVoiceClient.enableAudio(audioSession)
}
func provider(_ provider: CXProvider, didDeactivate audioSession: AVAudioSession) {
VGVoiceClient.disableAudio(audioSession)
}
}Cuando un usuario introduce un número e inicia una llamada, la aplicación solicita a CallKit que inicie la llamada. Si la solicitud tiene éxito, se llamará a la función CXStartCallAction que informa de la llamada saliente. Es muy importante tener en cuenta que VGVoiceClient.enableAudio/VGVoiceClient.disableAudio está siendo llamado aquí con la sesión de audio proporcionada por el CallKit CXProviderDelegate.
Actualización de laCallModel
Ahora que el ProviderManager está configurado, puede actualizar la clase CallModel para utilizarla. Abra el archivo ContentView.swift y sustituya las variables en la parte superior de la clase CallModel de la clase:
final class CallModel: NSObject, ObservableObject, VGVoiceClientDelegate {
@Published var status: String = ""
@Published var isCalling: Bool = false
private let client = VGVoiceClient()
var number: String = ""
private var callId: (vonage: String?, callkit: UUID?)
private let callController = CXCallController()
private let providerManager = ProviderManager()
private let audioSession = AVAudioSession.sharedInstance()
...
}callId ha cambiado a una tupla para gestionar la asignación de un ID de llamada de Vonage a un UUID de llamada de CallKit, providerManager así como callController. callController es una instancia de CXCallControllerque se utilizará para solicitar al sistema que inicie una llamada.
Actualización de lastartCall Función
La función startCall debe actualizarse para solicitar una llamada a través de la función callController cuando el usuario haga clic en la función de inicio de llamada. Sustituya la función existente por la nueva:
func startCall() {
isCalling = true
let handle = CXHandle(type: .phoneNumber, value: number)
self.callId.callkit = UUID()
let startCallAction = CXStartCallAction(call: self.callId.callkit!, handle: handle)
let transaction = CXTransaction(action: startCallAction)
callController.request(transaction) { _ in }
}Esta nueva función crea un UUID ya que CallKit necesita una forma de identificar la llamada, pero no obtendrás el ID de llamada de Vonage hasta que el SDK realice una llamada. Luego, se utiliza un CXStartCallAction se utiliza en un CXTransaction para solicitar una llamada. Esto llamará a la función CXStartCallAction en la función CXProviderDelegate definida anteriormente.
Actualización de laendCall Función
Del mismo modo, la función endCall para utilizarla con CallKit. Sustituya la función existente por la nueva:
func endCall() {
client.hangup(callId.vonage!) { error in
if error == nil {
if let callkitUUID = self.callId.callkit {
let transaction = CXTransaction(action: CXEndCallAction(call: callkitUUID))
self.callController.request(transaction) { _ in }
}
}
}
}Esta nueva función creó una CXEndCallAction acción, que se utiliza en un CXTransaction para solicitar la finalización de la llamada. Al solicitar la finalización de la llamada, el sistema es capaz de calcular la duración de la llamada con precisión. También es necesario manejar el caso en que la llamada se termina de forma remota. Actualice la función didReceiveHangupForCall en la función VGVoiceClientDelegate delegado:
func voiceClient(_ client: VGVoiceClient, didReceiveHangupForCall callId: VGCallId, withQuality callQuality: VGRTCQuality, reason: VGHangupReason) {
if let callkitUUID = self.callId.callkit {
providerManager.reportEndedCall(callUUID: callkitUUID)
}
resetState()
}Una vez más, esto garantiza que la finalización de la llamada se notifique, a través de la función providerManagerpara poder calcular con precisión la duración de la llamada.
Aplicación de laProviderManagerDelegate
Por último, implementa el ProviderManagerDelegate para que el providerManager pueda comunicar los cambios al CallModel:
extension CallModel: ProviderManagerDelegate {
func callReported(_ providerManager: ProviderManager, callUUID: UUID) {
client.serverCall(["to": number]) { error, callId in
if error == nil {
providerManager.reportOutgoingCall(callUUID: callUUID)
self.callId.vonage = callId
} else {
providerManager.reportFailedCall(callUUID: callUUID)
}
}
}
func providerReset() {
resetState()
}
}Cuando el providerManager ha informado la llamada al sistema con éxito, esta función delegada crea una llamada utilizando el Vonage Client SDK. Nuevamente, tanto en el caso de éxito como en el de error, la función providerManager se utiliza para informar el estado de la llamada al sistema. Ahora puedes realizar una llamada en la aplicación ejecutando el proyecto de Xcode en un dispositivo físico. Si miras las llamadas recientes en la app de teléfono en iOS, deberías ver tu llamada y el nombre de la app. Si haces clic en el icono de información, podrás ver también la duración de la llamada.

¿Y ahora qué?
Puede encontrar el proyecto completo en GitHub. Puedes hacer mucho más con el Client SDK y CallKit; puedes usar CallKit para llamadas salientes. Obtén más información sobre el Client SDK en la página Descripción general del Client SDK de Vonage y sobre CallKit en developer.apple.com.