Cómo leer la batería de iOS con Swift
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
12:30 min - 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
Cómo leer la batería de iOS con Swift
Resumen
Configurar la comunicación nativa entre Flutter y iOS exige tocar el AppDelegate.swift y conectar un Flutter Method Channel con el sistema operativo. Aquí aprendes a leer el nivel de batería del dispositivo desde Swift y devolver ese dato a Flutter, replicando la lógica que ya construiste en Android pero adaptada al ecosistema de Apple.
Cómo se estructura el AppDelegate.swift para usar Method Channel
El punto de partida vive dentro de la carpeta iOS, en el apartado Runner, donde encontrarás el archivo AppDelegate.swift con sus imports de Flutter y UIKit listos para extender.
La idea es agregar dos piezas: una función privada que consulte la batería del sistema y la lógica dentro de application que cree el canal de comunicación. Ambas se conectan mediante un handler que escucha las llamadas que llegan desde Dart.
¿Qué es un Method Channel en Flutter? Es el puente que permite a tu código Dart invocar funciones nativas en Android o iOS y recibir una respuesta. Funciona como un canal nombrado donde ambos lados acuerdan qué métodos existen.
Cómo crear la función privada getBatteryLevel en Swift
Dentro del AppDelegate declaras una función private func getBatteryLevel que recibe un parámetro result marcado con @escaping FlutterResult. Ese atributo escaping le dice a Swift que el closure puede ejecutarse después de que la función termine, algo común cuando hablas con APIs asíncronas.
El flujo dentro de la función es directo:
- Habilitar el monitoreo con
UIDevice.current.isBatteryMonitoringEnabled = true. - Capturar el valor con
let batteryLevel = UIDevice.current.batteryLevel. - Validar con un
ifquebatteryLevel >= 0antes de devolverlo. - Multiplicar por 100, convertir a
Inty concatenar el símbolo de porcentaje.
Si el valor es negativo, significa que iOS no pudo leer la batería. En ese caso devuelves un FlutterError con código "UNAVAILABLE", un mensaje descriptivo y details en nil. Esa estructura le permite a Flutter capturar el error como excepción y reaccionar en la UI.
Cómo conectar el FlutterViewController con el canal nativo
La segunda mitad del trabajo ocurre dentro del método application del AppDelegate. Ahí inicializas el controlador y registras el canal que escuchará las invocaciones desde Dart.
Primero defines el controlador con let controller = window?.rootViewController as! FlutterViewController. Ese cast con as! es lo que te permite acceder al binaryMessenger, una propiedad exclusiva del controlador de Flutter en iOS.
Luego creas el canal con FlutterMethodChannel(name: "native.communicator", binaryMessenger: controller.binaryMessenger). El name debe ser idéntico al que usaste en Android y en Dart, porque es el identificador que une los tres lados.
¿Por qué el name del canal debe coincidir en Android, iOS y Dart? Porque Flutter enruta las llamadas usando ese string como dirección. Si hay una diferencia de un carácter, el método nunca llega al lado nativo.
Cómo manejar las llamadas con setMethodCallHandler
Con el canal creado, llamas a batteryChannel.setMethodCallHandler y le pasas un closure que recibe dos parámetros: call: FlutterMethodCall y result: @escaping FlutterResult.
Dentro del closure va el ruteo de métodos:
- Un
if call.method == "getBatteryLevel"que invocaself?.getBatteryLevel(result: result). - Un
elseque responde conFlutterMethodNotImplementedcuando el nombre no coincide con ningún método registrado.
El uso de self aquí equivale a un this en otros lenguajes y permite acceder a la función privada que definiste arriba. Recuerda envolver todo el bloque del handler dentro de llaves y paréntesis para que Swift lo interprete como un closure válido.
Qué errores devolver cuando la batería no está disponible
La elegancia de este patrón está en separar éxito y fallo desde el nativo. Cuando todo funciona, mandas un string con el porcentaje. Cuando falla, mandas un FlutterError estructurado con tres campos:
code: un identificador corto como"UNAVAILABLE".message: una descripción legible para debugging.details: información extra opcional, en este casonil.
Ese contrato hace que el código Dart pueda usar try/catch limpio y mostrar mensajes apropiados en la UI sin acoplarse a la implementación de cada plataforma.
Con el AppDelegate listo, ya tienes la comunicación bidireccional configurada en Android y en iOS apuntando al mismo canal. Cuéntame en los comentarios si vas a usar este patrón para leer otra propiedad del sistema operativo en tu próximo proyecto.