Controlador de cámara iOS con FlutterError
Curso de Integración Módulos Nativos iOS/Android para Flutter
Contenido del curso
Introducción a TensorFlow Lite
Integración de modelos y clasificación de imágenes
Reconocimiento de voz con Whisper
MethodChannel
Acceso a sensores y cámara
- 16

Configuración de Method Channel para cámara en Android desde Flutter
10:53 min - 17

Cámara iOS nativa con MethodChannel en Flutter
12:36 min - 18

Configuración de permisos y provider para cámara en Android
10:12 min - 19

Configuración de permisos de cámara en iOS para Flutter
06:38 min - 20

Integración de cámara nativa iOS en Flutter con Method Channels
13:51 min - 21

Controlador de cámara iOS con FlutterError
Viendo ahora - 22

Implementación de cámara nativa en apps Android con Flutter
12:22 min
Gestión de estado con BLoC
Reconocimiento de texto en imágenes
- 25

Parseo de montos desde texto OCR con regex
07:08 min - 26

Integración de UI con cámara para captura de fotos en Flutter
06:19 min - 27

Cámara en Flutter con BLoC y modal
08:59 min - 28

Actualización de dependencias y corrección de errores en Flutter iOS
15:44 min - 29

Diferencias entre Flutter y React Native para desarrollo móvil
11:54 min
Controlador de cámara iOS con FlutterError
Resumen
Capturar una foto desde la cámara nativa de iOS con Flutter implica más que mostrar el picker: necesitas controlar qué pasa cuando el usuario toma la foto, cuando la cancela y cómo devolver esa información a tu canal de comunicación. Aquí construimos el controlador completo del UIImagePickerController, gestionamos el almacenamiento temporal de la imagen y emitimos errores claros hacia Flutter usando FlutterError.
¿Cómo crear el controlador del UIImagePickerController en iOS?
El primer paso es preparar la variable que va a guardar el resultado de la captura y luego implementar la función delegate que iOS dispara cuando el usuario termina de seleccionar una imagen.
Declaras un imageCaptureResult de tipo FlutterResult para devolver la respuesta a Flutter cuando la captura termine. Después implementas la función imagePickerController(_:didFinishPickingMediaWithInfo:), que recibe dos parámetros: el picker de tipo UIImagePickerController y un diccionario info con clave UIImagePickerController.InfoKey. Ese info trae todos los datos de la imagen seleccionada, incluyendo URL y path.
Dentro del cuerpo, lo primero es cerrar el picker con dismiss(animated: true, completion: nil) para replicar el comportamiento natural de las apps en iOS.
¿Qué hace didFinishPickingMediaWithInfo? Es el método delegate que iOS invoca cuando el usuario finaliza la selección de una imagen en el picker. Recibe el controlador y un diccionario con la información del archivo capturado.
¿Cómo guardar la imagen capturada con compresión JPEG?
Una vez cerrado el picker, validas que exista una imagen real dentro del diccionario info accediendo a la llave .originalImage y casteándola a UIImage.
Con la imagen ya en memoria, sigues estos pasos para almacenarla:
- Comprimir la imagen con
image.jpegData(compressionQuality: 0.8). El valor0.8define la calidad del JPEG en escala double de 0 a 1. - Construir el path temporal usando
FileManager.default.temporaryDirectory.appendingPathComponent("captureImage"). - Escribir el archivo con
try imageData?.write(to: path)para persistirlo en disco.
Esta secuencia te entrega un archivo físico que puedes referenciar después por su ruta. El uso del temporaryDirectory es clave: es el espacio que iOS asigna para archivos efímeros, así que no contaminas el almacenamiento permanente del usuario.
Cuando todo sale bien, completas el flujo invocando imageCaptureResult con el path de la imagen como argumento. Así Flutter recibe la ruta exacta donde quedó guardada la foto.
¿Qué es compressionQuality en jpegData? Es un valor double entre 0 y 1 que define la calidad del JPEG resultante. Un
0.8ofrece buena calidad visual con un tamaño de archivo razonable.
¿Cómo manejar errores cuando el usuario cancela la cámara?
El flujo feliz es solo la mitad del trabajo. Necesitas cubrir dos escenarios de error: cuando no se logra extraer la imagen del info y cuando el usuario presiona explícitamente el botón de cancelar.
Error cuando no se captura la imagen
Si la condición que valida la imagen falla, devuelves a Flutter un FlutterError con estos parámetros:
code:"imageError"para distinguirlo de otros errores del flujo.message:"no image captured"para describir qué ocurrió.details:nilporque no hay información adicional relevante.
Este error viaja por el mismo imageCaptureResult y Flutter lo recibe como una excepción manejable.
Cancelación explícita desde el botón Cancel
Para cuando el usuario toca Cancel en la UI nativa de iOS, implementas la función imagePickerControllerDidCancel(_:). Esta es más simple: solo cierra el picker con dismiss(animated: true, completion: nil) y devuelve un FlutterError con código "cancelado" y un mensaje indicando que el usuario canceló la operación.
Diferenciar ambos errores con códigos distintos (imageError vs cancelado) te permite reaccionar de forma específica desde el lado Dart, por ejemplo mostrando un toast solo cuando hubo un fallo real y no cuando el usuario simplemente cambió de opinión.
¿Cuándo se dispara imagePickerControllerDidCancel? Cuando el usuario presiona el botón de cancelar dentro del
UIImagePickerControllerde iOS. Es la señal nativa de que la operación se abortó intencionalmente.
¿Por qué importa devolver errores tipados a Flutter?
El FlutterError es el puente estándar entre código nativo y Dart cuando algo no sale como esperabas. Al construirlo con code, message y details, le das a tu capa Flutter información estructurada para tomar decisiones.
En este flujo concreto, distingues tres estados posibles desde el MethodChannel:
- Éxito: devuelves el path del archivo JPEG guardado en el directorio temporal.
- Imagen no capturada: devuelves
imageErrorcuando la información llega vacía o mal formada. - Usuario cancela: devuelves
canceladocuando se interrumpe el flujo por acción del usuario.
Con esta arquitectura, tu plugin de cámara responde de forma predecible a cualquier interacción y deja a la capa Flutter libre para mostrar la UI adecuada en cada caso. ¿Ya pensaste cómo vas a representar cada estado en tu pantalla? Comenta cómo lo manejarías tú.