# Method Channels: Comunicación con Nativo
Aunque Flutter pinta sus propios píxeles, a veces necesitas acceder a APIs de la plataforma (cámara, GPS, sensores, batería) o usar librerías nativas existentes en Android (Java/Kotlin) o iOS (Obj-C/Swift). Los **Method Channels** son el puente para esto.
## Arquitectura
La comunicación es asíncrona y basada en mensajes.
1. **Flutter (Cliente):** Envía un mensaje a través de un canal.
2. **Plataforma (Host):** Recibe el mensaje, ejecuta código nativo y devuelve una respuesta.
## Implementación en Flutter (Dart)
```dart
import 'package:flutter/services.dart';
class BatteryService {
// 1. Definir el canal (nombre único)
static const platform = MethodChannel('com.example.app/battery');
Future getBatteryLevel() async {
try {
// 2. Invocar método
final int result = await platform.invokeMethod('getBatteryLevel');
return 'Battery level: $result%';
} on PlatformException catch (e) {
return "Failed to get battery level: '${e.message}'.";
}
}
}
```
## Implementación en Android (Kotlin)
En tu `MainActivity.kt`:
```kotlin
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
class MainActivity: FlutterActivity() {
private val CHANNEL = "com.example.app/battery"
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler {
call, result ->
if (call.method == "getBatteryLevel") {
val batteryLevel = getBatteryLevel() // Tu lógica nativa
if (batteryLevel != -1) {
result.success(batteryLevel)
} else {
result.error("UNAVAILABLE", "Battery level not available.", null)
}
} else {
result.notImplemented()
}
}
}
private fun getBatteryLevel(): Int {
// Lógica real de Android...
return 100
}
}
```
## Implementación en iOS (Swift)
En tu `AppDelegate.swift`:
```swift
import UIKit
import Flutter
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
let batteryChannel = FlutterMethodChannel(name: "com.example.app/battery",
binaryMessenger: controller.binaryMessenger)
batteryChannel.setMethodCallHandler({
(call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
if call.method == "getBatteryLevel" {
// Tu lógica nativa
result(100)
} else {
result(FlutterMethodNotImplemented)
}
})
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
```
## Tipos de Datos
Flutter serializa automáticamente los tipos de datos comunes:
| Dart | Android (Kotlin) | iOS (Swift) |
|------|------------------|-------------|
| null | null | nil |
| bool | Boolean | Bool |
| int | Int/Long | Int/NSNumber |
| double | Double | Double/NSNumber |
| String | String | String |
| List | List | Array |
| Map | HashMap | Dictionary |
## Event Channels
Si necesitas un flujo continuo de datos (ej. datos del acelerómetro), usa `EventChannel`.
- **Flutter:** `EventChannel('...').receiveBroadcastStream().listen(...)`
- **Nativo:** Implementa `StreamHandler` (onListen, onCancel).
## Pigeon (Generación de Código)
Escribir Method Channels manualmente es propenso a errores (typos en nombres, tipos incorrectos). **Pigeon** es una herramienta oficial que genera el código de "pegamento" (glue code) type-safe automáticamente.
1. Defines la interfaz en Dart.
2. Ejecutas Pigeon.
3. Implementas la interfaz generada en Android/iOS.
4. Llamas a la clase generada en Dart.
## Conclusión
- Method Channels permiten a Flutter hablar con el mundo nativo.
- Es comunicación asíncrona.
- Usa `MethodChannel` para llamadas puntuales.
- Usa `EventChannel` para streams de datos.
- Considera **Pigeon** para proyectos grandes para garantizar seguridad de tipos.
Este apartado profundiza en los conceptos clave, proporcionando ejemplos prácticos y mejores prácticas para su aplicación en proyectos reales.
Al comprender estos detalles, podrás diseñar soluciones más robustas, mantenibles y escalables en tus aplicaciones Flutter y Dart.