Как реализуешь вызов нативного кода из Flutter?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Как реализуешь вызов нативного кода из Flutter?
Вызов нативного кода из Flutter реализуется через платформенные каналы (Platform Channels). Это основной механизм взаимодействия между кодом на Dart и нативным кодом платформы.
Основные подходы
1. MethodChannel — для синхронных и асинхронных вызовов
Это наиболее распространённый способ. MethodChannel позволяет вызывать методы нативного кода и получать результаты.
Flutter сторона (Dart):
import "package:flutter/services.dart";
class NativeCaller {
static const platform = MethodChannel("com.example.app/native");
Future<String> getBatteryLevel() async {
try {
final result = await platform.invokeMethod("getBatteryLevel");
return "Battery level: $result%";
} on PlatformException catch (e) {
return "Error: ${e.message}";
}
}
}
Android сторона (Kotlin):
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
class MainActivity: FlutterActivity() {
private val CHANNEL = "com.example.app/native"
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL)
.setMethodCallHandler { call, result ->
when (call.method) {
"getBatteryLevel" -> {
val batteryLevel = getBatteryLevel()
result.success(batteryLevel)
}
else -> result.notImplemented()
}
}
}
}
iOS сторона (Swift):
import Flutter
class AppDelegate: UIResponder, UIApplicationDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
let controller = window?.rootViewController as! FlutterViewController
let channel = FlutterMethodChannel(
name: "com.example.app/native",
binaryMessenger: controller.binaryMessenger
)
channel.setMethodCallHandler { (call: FlutterMethodCall, result: @escaping FlutterResult) in
switch call.method {
case "getBatteryLevel":
result(100)
default:
result(FlutterMethodNotImplemented)
}
}
return true
}
}
2. EventChannel — для потока событий
Используется, когда нативный код отправляет события в Flutter:
Flutter сторона:
class LocationListener {
static const stream = EventChannel("com.example.app/location");
Stream<Map<String, double>> getLocationUpdates() {
return stream.receiveBroadcastStream()
.cast<Map<dynamic, dynamic>>()
.map((dynamic event) => Map<String, double>.from(event));
}
}
3. BasicMessageChannel — для передачи сообщений
Для простого обмена сообщениями:
class Messenger {
static const channel = BasicMessageChannel(
"com.example.app/messages",
StringCodec()
);
Future<String> sendMessage(String message) async {
return await channel.send(message) as String;
}
}
Практический пример: доступ к GPS
class GeoLocation {
static const platform = MethodChannel("com.example.app/geolocation");
Future<Map<String, double>> getCurrentLocation() async {
try {
final Map<dynamic, dynamic> result =
await platform.invokeMethod("getCurrentLocation");
return {
"latitude": result["latitude"] as double,
"longitude": result["longitude"] as double
};
} catch (e) {
throw Exception("Ошибка получения геолокации");
}
}
}
Обработка ошибок
try {
await platform.invokeMethod("someMethod");
} on PlatformException catch (e) {
print("Code: ${e.code}");
print("Message: ${e.message}");
} on MissingPluginException {
print("Метод не реализован на платформе");
}
Типы данных и сериализация
Поддерживаемые типы: null, bool, int, double, String, Uint8List, List, Map.
await platform.invokeMethod("updateUser", {
"id": 123,
"name": "John Doe",
"tags": ["flutter", "mobile"]
});
Лучшие практики
- Обработка исключений — всегда оборачивайте вызовы в try-catch
- Константные имена каналов — используйте одно имя везде
- Типизация — явно указывайте типы результатов
- Асинхронность — не блокируйте основной поток
- Проверка наличия — убедитесь, что метод реализован на обеих сторонах
Платформенные каналы — это мощный инструмент для интеграции Flutter с нативным функционалом платформы.