Els canals de plataforma (Platform Channels) són una característica poderosa de Flutter que permet la comunicació entre el codi Dart i el codi natiu (Java/Kotlin per a Android i Objective-C/Swift per a iOS). Aquesta funcionalitat és essencial quan necessites accedir a funcionalitats específiques del sistema operatiu que no estan disponibles directament a través de Flutter.
Objectius d'Aprenentatge
- Comprendre què són els canals de plataforma i per què són necessaris.
- Aprendre a configurar un canal de plataforma bàsic.
- Implementar la comunicació entre Flutter i el codi natiu.
- Veure exemples pràctics d'ús de canals de plataforma.
Què són els Canals de Plataforma?
Els canals de plataforma permeten enviar missatges entre el codi Dart i el codi natiu. Això es fa mitjançant un canal de missatges que pot ser utilitzat per invocar mètodes natius des de Flutter i viceversa.
Components Clau
- MethodChannel: Utilitzat per enviar missatges des de Flutter a la plataforma nativa.
- EventChannel: Utilitzat per rebre fluxos d'esdeveniments des de la plataforma nativa a Flutter.
- BasicMessageChannel: Utilitzat per enviar missatges bàsics en ambdues direccions.
Configuració d'un Canal de Plataforma Bàsic
Pas 1: Configuració del Codi Dart
Primer, configurem el codi Dart per enviar un missatge al codi natiu.
import 'package:flutter/services.dart';
class PlatformChannelExample {
static const platform = MethodChannel('com.example.platform_channel');
Future<String> getNativeMessage() async {
try {
final String result = await platform.invokeMethod('getNativeMessage');
return result;
} on PlatformException catch (e) {
return "Error: '${e.message}'.";
}
}
}Pas 2: Configuració del Codi Natiu (Android)
A continuació, configurem el codi natiu per Android. Afegim el següent codi a MainActivity.kt o MainActivity.java.
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.platform_channel"
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler {
call, result ->
if (call.method == "getNativeMessage") {
val message = getNativeMessage()
result.success(message)
} else {
result.notImplemented()
}
}
}
private fun getNativeMessage(): String {
return "Hola des de Kotlin!"
}
}Java
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugin.common.MethodChannel;
public class MainActivity extends FlutterActivity {
private static final String CHANNEL = "com.example.platform_channel";
@Override
public void configureFlutterEngine(FlutterEngine flutterEngine) {
super.configureFlutterEngine(flutterEngine);
new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL)
.setMethodCallHandler(
(call, result) -> {
if (call.method.equals("getNativeMessage")) {
String message = getNativeMessage();
result.success(message);
} else {
result.notImplemented();
}
}
);
}
private String getNativeMessage() {
return "Hola des de Java!";
}
}Pas 3: Configuració del Codi Natiu (iOS)
Finalment, configurem el codi natiu per iOS. Afegim el següent codi a AppDelegate.swift o AppDelegate.m.
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 channel = FlutterMethodChannel(name: "com.example.platform_channel",
binaryMessenger: controller.binaryMessenger)
channel.setMethodCallHandler({
(call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
if call.method == "getNativeMessage" {
result(self.getNativeMessage())
} else {
result(FlutterMethodNotImplemented)
}
})
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
private func getNativeMessage() -> String {
return "Hola des de Swift!"
}
}Objective-C
#import "AppDelegate.h"
#import "GeneratedPluginRegistrant.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
FlutterViewController* controller = (FlutterViewController*)self.window.rootViewController;
FlutterMethodChannel* channel = [FlutterMethodChannel
methodChannelWithName:@"com.example.platform_channel"
binaryMessenger:controller.binaryMessenger];
[channel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
if ([@"getNativeMessage" isEqualToString:call.method]) {
result([self getNativeMessage]);
} else {
result(FlutterMethodNotImplemented);
}
}];
[GeneratedPluginRegistrant registerWithRegistry:self];
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
- (NSString*)getNativeMessage {
return @"Hola des de Objective-C!";
}
@endExemple Pràctic
Ara que hem configurat el canal de plataforma, podem utilitzar-lo en una aplicació Flutter. Aquí teniu un exemple pràctic:
import 'package:flutter/material.dart';
import 'platform_channel_example.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Canals de Plataforma'),
),
body: Center(
child: FutureBuilder<String>(
future: PlatformChannelExample().getNativeMessage(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return CircularProgressIndicator();
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
return Text('Missatge natiu: ${snapshot.data}');
}
},
),
),
),
);
}
}Exercici Pràctic
Objectiu
Implementar un canal de plataforma que permeti obtenir la versió del sistema operatiu des del codi natiu.
Instruccions
- Configura un canal de plataforma en el codi Dart.
- Implementa el codi natiu per Android i iOS per retornar la versió del sistema operatiu.
- Mostra la versió del sistema operatiu en una interfície d'usuari de Flutter.
Solució
Codi Dart
import 'package:flutter/services.dart';
class PlatformVersion {
static const platform = MethodChannel('com.example.platform_version');
Future<String> getPlatformVersion() async {
try {
final String version = await platform.invokeMethod('getPlatformVersion');
return version;
} on PlatformException catch (e) {
return "Error: '${e.message}'.";
}
}
}Codi Natiu (Android - Kotlin)
import android.os.Build
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.platform_version"
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler {
call, result ->
if (call.method == "getPlatformVersion") {
val version = "Android ${Build.VERSION.RELEASE}"
result.success(version)
} else {
result.notImplemented()
}
}
}
}Codi Natiu (iOS - 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 channel = FlutterMethodChannel(name: "com.example.platform_version",
binaryMessenger: controller.binaryMessenger)
channel.setMethodCallHandler({
(call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
if call.method == "getPlatformVersion" {
result("iOS " + UIDevice.current.systemVersion)
} else {
result(FlutterMethodNotImplemented)
}
})
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}Interfície d'Usuari de Flutter
import 'package:flutter/material.dart';
import 'platform_version.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Versió del Sistema Operatiu'),
),
body: Center(
child: FutureBuilder<String>(
future: PlatformVersion().getPlatformVersion(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return CircularProgressIndicator();
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
return Text('Versió del sistema operatiu: ${snapshot.data}');
}
},
),
),
),
);
}
}Conclusió
Els canals de plataforma són una eina essencial per accedir a funcionalitats específiques del sistema operatiu des de Flutter. Amb aquesta guia, has après a configurar un canal de plataforma bàsic i a implementar la comunicació entre Flutter i el codi natiu. Aquesta habilitat et permetrà crear aplicacions més riques i integrades amb les capacitats del dispositiu.
Curs de Desenvolupament Flutter
Mòdul 1: Introducció a Flutter
- Què és Flutter?
- Configuració de l'Entorn de Desenvolupament
- Comprensió de l'Arquitectura de Flutter
- Creació de la Teva Primera Aplicació Flutter
Mòdul 2: Conceptes Bàsics de Programació en Dart
- Introducció a Dart
- Variables i Tipus de Dades
- Sentències de Flux de Control
- Funcions i Mètodes
- Programació Orientada a Objectes en Dart
Mòdul 3: Widgets de Flutter
- Introducció als Widgets
- Widgets Stateless vs Stateful
- Widgets Bàsics
- Widgets de Disseny
- Widgets d'Entrada i Formulari
Mòdul 4: Gestió de l'Estat
Mòdul 5: Navegació i Enrutament
- Introducció a la Navegació
- Navegació Bàsica
- Rutes Nomenades
- Passar Dades Entre Pantalles
- Deep Linking
Mòdul 6: Xarxes i APIs
- Obtenir Dades d'Internet
- Analitzar Dades JSON
- Gestió d'Errors de Xarxa
- Ús d'APIs REST
- Integració de GraphQL
Mòdul 7: Persistència i Emmagatzematge
- Introducció a la Persistència
- Preferències Compartides
- Emmagatzematge de Fitxers
- Base de Dades SQLite
- Ús de Hive per a l'Emmagatzematge Local
Mòdul 8: Conceptes Avançats de Flutter
- Animacions en Flutter
- Pintura Personalitzada i Canvas
- Canals de Plataforma
- Isolates i Concurrència
- Optimització del Rendiment
Mòdul 9: Proves i Depuració
- Introducció a les Proves
- Proves Unitàries
- Proves de Widgets
- Proves d'Integració
- Tècniques de Depuració
Mòdul 10: Desplegament i Manteniment
- Preparació per al Llançament
- Construcció per a iOS
- Construcció per a Android
- Integració i Desplegament Continu (CI/CD)
- Manteniment i Actualització de la Teva Aplicació
