
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 hacer Video Llamadas con SwiftUI
Tiempo de lectura: 5 minutos
Este artículo se actualizó en marzo de 2025
En este tutorial, utilizará el SDK de Vonage Video Client SDK para iOS para construir un video chat uno a uno en SwiftUI.
Requisitos previos
Xcode 12 y Swift 5 o superior.
Crear un proyecto de Video API de Vonage
Abre tu panel de API de Vonage y crea una nueva aplicación de Vonage. Puedes llamarla como desees, pero habilita Video en las capacidades y luego haz clic en generar una nueva aplicación. Una vez creada la aplicación, copia el ID de la aplicación. Luego visita el Vonage Video Playground y crea una nueva sesión:
Asegúrese de que la pestaña "Crear una nueva sesión" está seleccionada en la parte superior.
Seleccione "Sí" en "¿Dispone de un ID de aplicación específico?".
Pegue el ID de aplicación que generó antes en el cuadro "ID de aplicación" que aparece.
Deje todo lo demás como está y haga clic en "Crear sesión".
En la página siguiente, anote el "ID de sesión".
Haz clic en el botón "Conectar" de la parte superior.
Despliegue la sección "Información de sesión y token" en la parte superior.
Anote el "TOKEN" que se ha generado
Creación de la aplicación iOS
El siguiente paso es configurar la aplicación para iOS. Una vez creada la aplicación, hay que instalar el Video Client SDK y pedir permisos para el micrófono y la cámara.
Crear un proyecto Xcode
Para empezar, abre Xcode y crea un nuevo proyecto yendo a Archivo > Nuevo > Proyecto. Selecciona iOS como plataforma y App para la plantilla y dale un nombre.

Selecciona SwiftUI para la interfaz, SwiftUI App para el ciclo de vida, y Swift para el lenguaje. Por último, una ubicación para guardar tu proyecto.

Instalar el Client SDK
Ahora que has creado el proyecto, puedes añadir el Video Client SDK como dependencia. Cierra tu proyecto Xcode y navega a la ubicación donde guardaste el proyecto en tu terminal y ejecuta los siguientes comandos:
Ejecute el comando pod init para crear un nuevo Podfile para su proyecto.
Abra el Podfile en Xcode usando open -a Xcode Podfile.
Actualiza el Podfile para que tenga
OTXCFrameworkcomo dependencia.
# Uncomment the next line to define a global platform for your project
# platform :ios, '12.0'
target 'VideoChat' do
# Comment the next line if you don't want to use dynamic frameworks
use_frameworks!
# Pods for VideoChat
pod 'OTXCFramework'
endInstale el SDK con
pod install.Abra el nuevo xcworkspace en Xcode con
open VideoChat.xcworkspace.
Permisos
Dado que la aplicación utilizará el micrófono y la cámara para el videochat, deberás añadir descripciones de por qué necesitas los permisos, que se mostrarán en un aviso al ejecutar la aplicación.
Edite el Info.plist archivo. El Info.plist es un archivo que contiene todos los metadatos necesarios para la aplicación. Añada una nueva entrada al archivo pasando el ratón por encima de la última entrada de la lista y haga clic en el pequeño botón + que aparece. En la lista desplegable, seleccione Privacy - Microphone Usage Description y añada Microphone access required to video chat como valor. Repita los pasos para Privacy - Camera Usage Description.
El Client SDK de Video
El Video Client SDK utiliza las credenciales que creaste en el panel de la Video API para conectarse a los servidores de Vonage.
Conexión del Client SDK
Cree un nuevo archivo llamado OpenTokManager.swift accediendo a Archivo > Nuevo archivo (CMD + N) y añada lo siguiente, sustituyendo las cadenas vacías por sus credenciales:
import OpenTok
final class OpenTokManager: NSObject, ObservableObject {
// Replace with your Vonage Application ID
private let kAppId = ""
// Replace with your generated session ID
private let kSessionId = ""
// Replace with your generated token
private let kToken = ""
private lazy var session: OTSession = {
return OTSession(apiKey: kAppId, sessionId: kSessionId, delegate: self)!
}()
private lazy var publisher: OTPublisher = {
let settings = OTPublisherSettings()
settings.name = UIDevice.current.name
return OTPublisher(delegate: self, settings: settings)!
}()
private var subscriber: OTSubscriber?
@Published var pubView: UIView?
@Published var subView: UIView?
@Published var error: OTErrorWrapper?
}Además de las credenciales, existen variables para una sesión, editor y abonado. Como se mencionó anteriormente, se puede pensar en una sesión como una sala a la que se conectan los clientes; el SDK tiene la clase OTSession para ello. Publicadores, OTPublisherpermiten al cliente publicar audio y video cuando se conecta a una sesión. Suscriptores, OTSubscriberpermiten al cliente suscribirse a audio y video de otros clientes en la sesión. También hay variables que utilizan el @Published que es la forma en que la clase OpenTokManager se comunicará con el código de la vista más adelante.
Ahora que las propiedades están en su lugar, añada las siguientes funciones a la clase OpenTokManager clase:
import OpenTok
final class OpenTokManager: NSObject, ObservableObject {
...
public func setup() {
doConnect()
}
private func doConnect() {
var error: OTError?
defer {
processError(error)
}
session.connect(withToken: kToken, error: &error)
}
private func doPublish() {
var error: OTError?
defer {
processError(error)
}
session.publish(publisher, error: &error)
if let view = publisher.view {
DispatchQueue.main.async {
self.pubView = view
}
}
}
private func doSubscribe(_ stream: OTStream) {
var error: OTError?
defer {
processError(error)
}
subscriber = OTSubscriber(stream: stream, delegate: self)
session.subscribe(subscriber!, error: &error)
}
private func cleanupSubscriber() {
DispatchQueue.main.async {
self.subView = nil
}
}
private func cleanupPublisher() {
DispatchQueue.main.async {
self.pubView = nil
}
}
private func processError(_ error: OTError?) {
if let err = error {
DispatchQueue.main.async {
self.error = OTErrorWrapper(error: err.localizedDescription)
}
}
}
}
La función doConnect conecta al cliente a la sesión, doPublish inicia la publicación, doSubscribe comienza a suscribirse. Luego hay funciones para limpiar el suscriptor (cleanupSubscriber) y el publicador (cleanupPublisher) cuando el cliente se desconecta de cualquiera de ellas, seguidas de una función para gestionar errores (processError).
EnOTSessionDelegate
El OTSessionDelegate es la forma en que el Video Client SDK le comunica los cambios realizados en la sesión. Añade una extensión en el mismo archivo:
extension OpenTokManager: OTSessionDelegate {
func sessionDidConnect(_ session: OTSession) {
print("Session connected")
doPublish()
}
func sessionDidDisconnect(_ session: OTSession) {
print("Session disconnected")
}
func session(_ session: OTSession, didFailWithError error: OTError) {
print("session Failed to connect: \(error.localizedDescription)")
}
func session(_ session: OTSession, streamCreated stream: OTStream) {
print("Session streamCreated: \(stream.streamId)")
doSubscribe(stream)
}
func session(_ session: OTSession, streamDestroyed stream: OTStream) {
print("Session streamDestroyed: \(stream.streamId)")
if let subStream = subscriber?.stream, subStream.streamId == stream.streamId {
cleanupSubscriber()
}
}
}Cuando se conecta la sesión doPublish cuando se crea un flujo doSubscribe y cuando se destruye el flujo cleanupSubscriber se llama.
EnOTPublisherDelegate
El OTPublisherDelegate es la forma en que el Video Client SDK le comunica los cambios con la publicación de una sesión. Añade una extensión en el mismo archivo:
extension OpenTokManager: OTPublisherDelegate {
func publisher(_ publisher: OTPublisherKit, streamCreated stream: OTStream) {
print("Publishing")
}
func publisher(_ publisher: OTPublisherKit, streamDestroyed stream: OTStream) {
cleanupPublisher()
if let subStream = subscriber?.stream, subStream.streamId == stream.streamId {
cleanupSubscriber()
}
}
func publisher(_ publisher: OTPublisherKit, didFailWithError error: OTError) {
print("Publisher failed: \(error.localizedDescription)")
}
}De forma similar al OTSessionDelegate cuando se destruye el flujo, cleanupPublisher se llama a cleanupSubscriber si hay una suscripción activa a un flujo.
EnOTSubscriberDelegate
El OTSubscriberDelegate es la forma en que el Video Client SDK le comunica los cambios al suscribirse a una sesión. Añade una extensión en el mismo archivo:
extension OpenTokManager: OTSubscriberDelegate {
func subscriberDidConnect(toStream subscriberKit: OTSubscriberKit) {
if let view = subscriber?.view {
DispatchQueue.main.async {
self.subView = view
}
}
}
func subscriber(_ subscriber: OTSubscriberKit, didFailWithError error: OTError) {
print("Subscriber failed: \(error.localizedDescription)")
}
}De forma similar a cuando se publica en una sesión, si la suscripción tiene éxito, se devuelve un UIView objeto En el caso de subscriberDidConnect el objeto de vista que se devuelve es para el suscriptor.
Creación de la interfaz de Video Chat
Con la clase OpenTokManager completa, ya puede crear la interfaz de usuario. El Client SDK de Video te proporciona UIView para las vistas de editor y suscriptor que no pueden ser utilizadas directamente en SwiftUI. El protocolo UIViewRepresentable permite pasar de un objeto UIView a un objeto View objeto para SwiftUI. En el archivo ContentView.swift añade los siguientes structs:
struct OTErrorWrapper: Identifiable {
var id = UUID()
let error: String
}
struct OTView: UIViewRepresentable {
@State var view: UIView
func makeUIView(context: Context) -> UIView {
return view
}
func updateUIView(_ uiView: UIView, context: Context) {
DispatchQueue.main.async {
self.view = uiView
}
}
}
La estructura OTView struct, que se ajusta a UIViewRepresentable tiene un objeto UIView como propiedad. Esta vista se devuelve cuando el sistema llama a makeUIView. Dado que el ciclo de vida de las vistas en SwiftUI está controlado por el sistema, también necesitas implementarupdateUIViewpara manejarlo. La estructuraOTErrorWrapperpermite que el error se ajuste aIdentifiableque es necesario para utilizar las alertas de SwiftUI.
A continuación, sustituya la estructura ContentView struct por lo siguiente:
struct ContentView: View {
@ObservedObject var otManager = OpenTokManager()
var body: some View {
VStack {
otManager.pubView.flatMap { view in
OTView(view: view)
.frame(width: 200, height: 200, alignment: .center)
}.cornerRadius(5.0)
otManager.subView.flatMap { view in
OTView(view: view)
.frame(width: 200, height: 200, alignment: .center)
}.cornerRadius(5.0)
}
.alert(item: $otManager.error, content: { error -> Alert in
Alert(title: Text("OpenTok Error"), message: Text(error.error), dismissButton: .default(Text("Ok")))
})
.animation(.default)
.onAppear(perform: {
otManager.setup()
})
}
}
Este código añade una propiedad para una instancia de la clase OpenTokManager de antes. Dado que las vistas que OpenTokManager está publicando son opcionales, .flatmap se utiliza. Así que cuando las vistas son nulas, se ignoran, y cuando hay un valor, se desenvuelven. Si el OpenTokManager publica un error, la alerta se mostrará automáticamente ya que está pendiente de los cambios en el valor publicado. .error publicado.
Si construyes y ejecutas el proyecto, ¡ya deberías poder iniciar un videochat! Puedes utilizar otro dispositivo o la Video API Playground para conectarte a la sesión desde tu portátil.

¿Y ahora qué?
El proyecto completo está disponible en GitHuby puedes obtener más información sobre la Video API de Vonage en nuestra documentación.