Platform Kanalları: Swift ve Kotlin Yerel Kodunu Entegre Etme
Flutter, uygulama özelliklerinin %90'ı için mükemmeldir, ancak bunlar mevcuttur platformun yerel API'lerine doğrudan erişmeniz gereken durumlar: biyometrik sensörler, Bluetooth LE, Apple Pay, Google Pay, dosya sistemi erişimi yerel, üçüncü taraf SDK'larla entegrasyon Flutter eklentileri olarak mevcut değildir. Bu durumlar için Platform Kanalları.
Platform Kanalları Dartlar arasında iki yönlü bir iletişim köprüsü oluşturur ve yerel kod (iOS'ta Swift, Android'de Kotlin). Java yazmıyorsun o Eski Objective-C: Eşyordamlar ve eşzamansız/beklemeli modern Kotlin ve Swift sırasıyla. Bu kılavuzda aşağıdakilere erişen eksiksiz bir eklenti oluşturuyoruz: cihazın yakınlık sensörüne; Flutter çekirdeğinde mevcut değildir.
Ne Öğreneceksiniz
- MethodChannel: Dart → yanıtlı yerel çağrılar (istek/yanıt)
- EventChannel: Yerel → Dart'tan sürekli veri akışı
- BasicMessageChannel: yapılandırılmamış çift yönlü iletişim
- Hata işleme: Her iki yönden de PlatformException
- İş parçacığı: ana iş parçacığı, arka plan iş parçacığı, FlutterEngine
- Eklenti paketi: Yeniden kullanılabilir eklentilere yönelik yapı
- Güvercin: Platform Kanalları için tür açısından güvenli kod üretimi
MethodChannel: Eşzamanlı İstek/Yanıt
Il YöntemKanal ve en yaygın kanal türü: Dart kodu yerel bir yöntemi çağırır ve yanıt bekler. Tek seferlik operasyonlar için ideal cihaz hakkında bilgi nasıl alınır, yerel ekran nasıl açılır, biyometrik bir işlem gerçekleştirin.
// lib/proximity_sensor.dart: interfaccia Dart
import 'package:flutter/services.dart';
class ProximitySensor {
static const _channel = MethodChannel('com.example.proximity_sensor');
// Verifica se il sensore e disponibile
static Future<bool> isAvailable() async {
try {
final bool result = await _channel.invokeMethod('isAvailable');
return result;
} on PlatformException catch (e) {
// PlatformException: errore dal codice nativo
debugPrint('ProximitySensor.isAvailable error: ${e.code} - ${e.message}');
return false;
} on MissingPluginException {
// Plugin non registrato (es. desktop non supporta il sensore)
return false;
}
}
// Ottieni la distanza attuale (in cm, 0 = vicino, null = non disponibile)
static Future<double?> getDistance() async {
try {
final double? distance = await _channel.invokeMethod<double>('getDistance');
return distance;
} on PlatformException catch (e) {
throw ProximitySensorException(e.code, e.message ?? 'Unknown error');
}
}
}
class ProximitySensorException implements Exception {
final String code;
final String message;
const ProximitySensorException(this.code, this.message);
@override
String toString() => 'ProximitySensorException($code): $message';
}
// android/src/main/kotlin/.../ProximitySensorPlugin.kt
// Implementazione Android con Kotlin
package com.example.proximity_sensor
import android.content.Context
import android.hardware.Sensor
import android.hardware.SensorManager
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
class ProximitySensorPlugin : FlutterPlugin, MethodChannel.MethodCallHandler {
private lateinit var channel: MethodChannel
private lateinit var context: Context
override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {
context = binding.applicationContext
channel = MethodChannel(
binding.binaryMessenger,
"com.example.proximity_sensor"
)
channel.setMethodCallHandler(this)
}
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
when (call.method) {
"isAvailable" -> {
val sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY)
result.success(sensor != null)
}
"getDistance" -> {
val sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY)
if (sensor == null) {
// Errore: ritorna PlatformException a Dart
result.error(
"SENSOR_NOT_FOUND",
"Proximity sensor not available on this device",
null
)
return
}
// Leggi il valore attuale (semplificato: usa EventChannel per stream)
result.success(sensor.maximumRange.toDouble())
}
else -> result.notImplemented()
}
}
override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
channel.setMethodCallHandler(null)
}
}
// ios/Classes/ProximitySensorPlugin.swift
// Implementazione iOS con Swift
import Flutter
import UIKit
public class ProximitySensorPlugin: NSObject, FlutterPlugin {
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(
name: "com.example.proximity_sensor",
binaryMessenger: registrar.messenger()
)
let instance = ProximitySensorPlugin()
registrar.addMethodCallDelegate(instance, channel: channel)
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
switch call.method {
case "isAvailable":
// iOS ha sempre il sensore di prossimita nei modelli standard
result(UIDevice.current.isProximityMonitoringEnabled ||
ProcessInfo.processInfo.environment["SIMULATOR_DEVICE_NAME"] == nil)
case "getDistance":
UIDevice.current.isProximityMonitoringEnabled = true
let isNear = UIDevice.current.proximityState
// Conversione in float: 0.0 = lontano, 1.0 = vicino
let distance: Double = isNear ? 0.0 : 10.0
result(distance)
default:
result(FlutterMethodNotImplemented)
}
}
}
EventChannel: Sürekli Veri Akışı
L'Etkinlik Kanalı ve veri akışı için tasarlandı: sensörler sürekli güncellenen, coğrafi konum olayları, donanım bildirimleri. Yerel, widget'ın dinleyebileceği bir Dart akışına olaylar yayar StreamBuilder.
// Dart: EventChannel per stream del sensore di prossimita
class ProximitySensorStream {
static const _eventChannel = EventChannel('com.example.proximity_sensor/stream');
static Stream<double> get proximityStream {
return _eventChannel
.receiveBroadcastStream()
.map((event) => (event as double));
}
}
// Widget: StreamBuilder per visualizzare i dati in tempo reale
class ProximitySensorWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return StreamBuilder<double>(
stream: ProximitySensorStream.proximityStream,
builder: (context, snapshot) {
if (snapshot.hasError) {
return Text('Errore: ${snapshot.error}');
}
if (!snapshot.hasData) {
return const CircularProgressIndicator();
}
final distance = snapshot.data!;
return Column(
children: [
Text('Distanza: ${distance.toStringAsFixed(1)} cm'),
Icon(
distance < 5 ? Icons.phone_in_talk : Icons.phone_android,
size: 48,
color: distance < 5 ? Colors.red : Colors.green,
),
],
);
},
);
}
}
// Kotlin: EventChannel sul lato Android
class ProximitySensorStreamHandler(
private val context: Context
) : EventChannel.StreamHandler {
private var sensorManager: SensorManager? = null
private var sensorListener: SensorEventListener? = null
override fun onListen(arguments: Any?, events: EventChannel.EventSink) {
sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensor = sensorManager?.getDefaultSensor(Sensor.TYPE_PROXIMITY)
if (sensor == null) {
events.error("SENSOR_NOT_FOUND", "No proximity sensor", null)
return
}
sensorListener = object : SensorEventListener {
override fun onSensorChanged(event: SensorEvent) {
// Invia ogni aggiornamento al Dart stream
events.success(event.values[0].toDouble())
}
override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {}
}
sensorManager?.registerListener(sensorListener, sensor, SensorManager.SENSOR_DELAY_NORMAL)
}
override fun onCancel(arguments: Any?) {
// Pulisci le risorse quando lo stream viene cancellato
sensorManager?.unregisterListener(sensorListener)
sensorManager = null
sensorListener = null
}
}
Güvercin: Kod Oluşturma Türü Güvenli
Güvercin ve kodu oluşturmak için resmi Flutter aracı Paylaşılan bir Dart tanımından Platform Kanalları ortak metni. Manuel serileştirmeyi yönetme ihtiyacını ortadan kaldırır ve garanti eder Dart ve yerel kodun senkronize olduğunu.
// pigeons/proximity.dart: definizione dell'interfaccia (source of truth)
import 'package:pigeon/pigeon.dart';
@ConfigurePigeon(PigeonOptions(
dartOut: 'lib/proximity_api.g.dart',
kotlinOut: 'android/src/main/kotlin/com/example/ProximityApi.g.kt',
swiftOut: 'ios/Classes/ProximityApi.g.swift',
))
// Messaggi (data classes)
class ProximityInfo {
final double distance;
final bool isNear;
const ProximityInfo({required this.distance, required this.isNear});
}
// HostApi: metodi implementati nel codice nativo, chiamati da Dart
@HostApi()
abstract class ProximityHostApi {
bool isAvailable();
ProximityInfo getCurrentReading();
}
// FlutterApi: metodi implementati in Dart, chiamati dal nativo
@FlutterApi()
abstract class ProximityFlutterApi {
void onProximityChanged(ProximityInfo info);
}
// Genera il codice:
// flutter pub run pigeon --input pigeons/proximity.dart
Platform Kanalları ve Mevcut Eklentiler Ne Zaman Kullanılmalı?
- Platform Kanallarını yazmadan önce: zaten bir eklentinin mevcut olup olmadığını görmek için pub.dev'de arama yapın
- pub.dev'in 40.000'den fazla paketi var: yerel API'lerin çoğu zaten kapsanıyor
- Platform Kanallarını şunlar için kullanın: Kurumsal tescilli SDK'lar, çok özel API'ler, mevcut yerel eski kodla entegrasyon
- Yeni paylaşılabilir eklentiler için: Tip güvenliği ve daha az bakım için Pigeon'u kullanın
Sonuçlar
Platform Kanalları Flutter'ı gerçekten evrensel kılan mekanizmadır: herhangi bir yerel API'ye sahiptir ve MethodChannel veya EventChannel ile ulaşılabilir. Güvercin Tip güvenliği ekler ve standartların çoğunu ortadan kaldırır. anahtarı iyi yerel entegrasyon ve hataları doğru şekilde ele alma PlatformException ve kaynakları temizleme (dinleyicinin kaydını iptal etme, akışı iptal etme) doğru yaşam döngüsünde.







