Contenido del curso

Integración Nativa en iOS 18

Acceso nativo a la cámara iOS con AVFoundation

Resumen

Acceder a la cámara nativa en iOS con AVFoundation requiere configurar permisos, sesiones de captura y procesamiento de fotogramas sin depender de librerías externas. Aprenderás a estructurar un CameraHandler en Swift para capturar video o imágenes desde la cámara trasera, manejar permisos en tiempo real y mostrar el resultado en una vista de SwiftUI. Es relevante para desarrolladores iOS que buscan integrar funcionalidades multimedia de forma segura y siguiendo buenas prácticas del App Store.

Qué variables necesitas para capturar imagen y video en iOS

Antes de pedir permisos o iniciar la cámara, debes declarar las variables que sostendrán toda la lógica de captura. Cada una cumple un rol específico dentro del flujo.

  • frame: variable publicada de tipo CGImage opcional, porque al cancelar la captura no habrá valor.
  • permissionGranted: variable privada que indica si el usuario otorgó acceso a la cámara.
  • captureSession: instancia de AVCaptureSession, dependencia base para capturar imagen o video [3:00].
  • sessionQueue: una DispatchQueue que actúa como cola de peticiones para no bloquear el hilo principal.
  • ciContext: contexto de Core Image para procesar los fotogramas capturados.

¿Para qué sirve AVCaptureSession? Es la clase de AVFoundation que coordina entradas (cámara) y salidas (video o imagen) durante una sesión de captura en iOS.

Cómo solicitar permisos de cámara en iOS de forma nativa

Apple obliga a pedir permisos en contexto, justo cuando vas a usar el recurso. Antes, en Android se otorgaban todos los permisos al instalar, lo que abría la puerta a apps que robaban información sin que el usuario lo notara. Hoy ese modelo cambió y iOS marcó la pauta.

Cómo verifico si el usuario autorizó la cámara

Dentro del init sobrecargado, llamas a super.init() y luego ejecutas una función checkPermission que evalúa el estado actual con un switch sobre AVCaptureDevice.authorizationStatus(for: .video) [8:00].

  • authorized: asignas self.permissionGranted = true.
  • notDetermined: llamas a requestPermission para volver a preguntar y evitar recursión infinita.
  • default: el permiso está denegado y asignas false.

El error más común al iniciar este flujo es llamar a checkPermission dentro del caso notDetermined, lo que genera una llamada recursiva. La solución es invocar requestPermission en su lugar.

Cómo solicito el acceso con requestPermission

Esta función usa AVCaptureDevice.requestAccess(for: .video) y dentro del completionHandler actualiza self.permissionGranted con el valor granted que devuelve el sistema. Aquí es donde aparece el cuadro de diálogo intrusivo que Apple exige.

¿Por qué el diálogo de permisos es tan intrusivo? Porque obliga al usuario a ser consciente de qué información comparte. Esa fricción es una capa de seguridad deliberada.

Cómo configuro NSCameraUsageDescription en Info.plist

Sin esta clave, la app crashea al pedir permisos y el App Store puede rechazar la publicación. Ve al directorio principal del proyecto, pestaña Info, y agrega Privacy - Camera Usage Description [15:30].

La descripción debe ser específica. No basta con escribir obtenemos ubicación o necesitamos la cámara. Apple rechaza apps con descripciones vagas. Un ejemplo válido: La cámara es necesaria para almacenar fotografías dentro de la aplicación. Cuanto más concreto el motivo, menor el riesgo de rebote en la revisión.

Cómo configurar la sesión de captura con setupCaptureSession

Una vez verificado el permiso, configuras la entrada y salida de datos dentro de una función asíncrona ejecutada en la sessionQueue.

Cómo obtengo la cámara trasera del dispositivo

Declaras videoOutput como AVCaptureVideoDataOutput y validas que permissionGranted sea verdadero. Si no lo es, sales de la función. Después accedes al hardware con AVCaptureDevice.default(.builtInDualCamera, for: .video, position: .back), que devuelve la cámara trasera con capacidades duales [19:00].

El flujo incluye tres validaciones encadenadas con guard:

  1. Que exista un dispositivo de cámara disponible.
  2. Que se pueda crear un AVCaptureDeviceInput a partir de ese dispositivo.
  3. Que la sesión pueda añadir esa entrada con captureSession.canAddInput.

Cualquier fallo en estas validaciones detiene el proceso. Tiene sentido: la cámara es hardware, y el hardware falla.

Cómo proceso los fotogramas y configuro la orientación

Después de añadir la entrada, configuras la salida con videoOutput.setSampleBufferDelegate(self, queue: DispatchQueue(label: "sampleBufferQueue")) y la añades con captureSession.addOutput(videoOutput).

La orientación cambia según la versión de iOS [25:00]:

  • iOS 17 o superior: usa connection.videoRotationAngle = 90.
  • Versiones anteriores: usa connection.videoOrientation = .portrait.

Sin este ajuste, el video se muestra al revés. Una extensión del CameraHandler procesa cada fotograma del buffer, lo convierte en CGImage y actualiza la variable frame en el hilo principal para que la interfaz lo consuma.

Cómo muestro la captura en una vista de SwiftUI

Creas una estructura CameraView con dos propiedades: image: CGImage? y label: String. Dentro del body, evalúas con if let si existe imagen.

  • Si no hay imagen, muestras un Color.red como placeholder.
  • Si hay imagen, renderizas un Image(cgImage, scale: 1.0, orientation: .up, label: Text(label)).

Luego, en DemoCameraView, declaras @StateObject private var model = CameraHandler() e instancias CameraView pasándole model.frame. Aplicas .ignoresSafeArea() para pantalla completa.

¿Qué pasa si pruebo la cámara en el simulador de Xcode? No funciona. El simulador no tiene acceso a hardware de cámara, así que necesitas un dispositivo físico para validar la captura real.

Por qué validar permisos y hardware en cada paso

La cámara es un recurso compartido y físico. Validar permisos, existencia del dispositivo y disponibilidad de la sesión en cada paso evita crashes y mejora la experiencia. Si el permiso no fue otorgado, la función sale temprano. Si la cámara está dañada, también. Y si no se puede añadir la entrada al flujo, la app no avanza.

Este patrón de early return mantiene el código limpio y previene errores en producción que serían imposibles de reproducir desde tu máquina de desarrollo.

¿Ya probaste integrar AVFoundation en tu propio proyecto? Cuéntanos en los comentarios qué validaciones agregaste tú.

      Acceso nativo a la cámara iOS con AVFoundation