Ответ
BasicMessageChannel — это один из трёх основных каналов платформенных каналов (Platform Channels) в Flutter, предназначенный для асинхронной передачи простых сообщений (строк, чисел, списков, мап) между кодом на Dart и нативным кодом платформы (Kotlin/Java для Android, Swift/Obj-C для iOS).
Зачем он нужен? Для вызова нативных API, которые не имеют готовых плагинов, например, для работы со специфичным hardware, системными сервисами или нативными библиотеками.
Пример двухсторонней коммуникации (Dart <-> Kotlin):
1. Сторона Dart (Flutter):
import 'package:flutter/services.dart';
// Создаем канал. Имя 'com.example/app_channel' должно быть уникальным.
const _channel = BasicMessageChannel<String>(
'com.example/app_channel',
StringCodec(), // Используем стандартный кодек для строк
);
// Отправляем сообщение на платформу и ждем ответ
Future<void> sendMessageToNative() async {
String response;
try {
final String reply = await _channel.send('Hello from Flutter!');
response = 'Received reply: $reply';
} on PlatformException catch (e) {
response = 'Failed: ${e.message}';
}
print(response);
}
// Устанавливаем обработчик входящих сообщений с платформы
@override
void initState() {
super.initState();
_channel.setMessageHandler((String? message) async {
print('Flutter received: $message');
// Можно отправить ответ обратно
return 'Ack from Flutter';
});
}
2. Сторона Kotlin (Android):
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.BasicMessageChannel
import io.flutter.plugin.common.StringCodec
class MainActivity: FlutterActivity() {
private var channel: BasicMessageChannel<String>? = null
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
// Создаем канал с таким же именем
channel = BasicMessageChannel(
flutterEngine.dartExecutor.binaryMessenger,
"com.example/app_channel",
StringCodec.INSTANCE
)
// Устанавливаем обработчик
channel?.setMessageHandler { message, reply ->
Log.d("Native", "Received from Flutter: $message")
// Отправляем ответ во Flutter
reply.reply("Hello from Android!")
}
}
}
Ключевое отличие от других каналов:
- MethodChannel: Используется для вызова конкретных методов (как API).
- EventChannel: Для передачи потока событий (stream) от платформы к Dart.
- BasicMessageChannel: Для свободного обмена сообщениями, когда структура вызовов не фиксирована строго в "методы".
Ответ 18+ 🔞
А, ну это ж классика! BasicMessageChannel, ёпта. Представь, что у тебя есть два чувака в разных комнатах — один на Dart'е сидит, другой в нативном коде ковыряется. И им надо перекинуться записками. Ну вот этот канал — он и есть та самая дырка в стене, куда они эти записки суют. Асинхронно, блядь, чтобы никто никого не ждал, пока тот поссать сходит.
Зачем он, этот BasicMessageChannel? Да всё просто, чувак! Когда тебе надо дернуть какой-нибудь нативный функционал, на который ещё ни один ленивый пидарас шерстяной плагин не написал. Хочешь батарейку проверить специфично? Или со сканером отпечатков своего производителя пообщаться? Вот тут он и пригодится. Прямой проводок, без посредников.
Смотри, как они переписываются. Сначала наш Флаттер-чувак (сторона Dart):
import 'package:flutter/services.dart';
// Создаём канал. Имя 'com.example/app_channel' — это типа пароль,
// чтоб только свои свои записки забирали. Должно совпадать с тем, что в нативе.
const _channel = BasicMessageChannel<String>(
'com.example/app_channel',
StringCodec(), // Кодек для строк. Чтоб не иероглифы пришли, а нормальный текст.
);
// Кидаем записку нативу и ждём ответа, как дурачки
Future<void> sendMessageToNative() async {
String response;
try {
// Отправляем "Привет!" и терпеливо пялимся в дырку
final String reply = await _channel.send('Hello from Flutter!');
response = 'Received reply: $reply';
} on PlatformException catch (e) {
// Если натив обосрался и кинул исключение — ловим тут
response = 'Failed: ${e.message}';
}
print(response);
}
// А это если натив захочет нам что-то сказать первым. Вешаем слушателя на дырку.
@override
void initState() {
super.initState();
_channel.setMessageHandler((String? message) async {
print('Flutter received: $message'); // Опа, записка!
// Можем сразу ответить, типа "Получил, братан"
return 'Ack from Flutter';
});
}
А теперь наш нативный кореш в Котлине (Android):
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.BasicMessageChannel
import io.flutter.plugin.common.StringCodec
class MainActivity: FlutterActivity() {
private var channel: BasicMessageChannel<String>? = null
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
// Создаём ТОЧНО ТАКОЙ ЖЕ канал. Имя — тот же пароль.
channel = BasicMessageChannel(
flutterEngine.dartExecutor.binaryMessenger,
"com.example/app_channel", // Смотри, чтоб буква в букву!
StringCodec.INSTANCE
)
// И тоже вешаем ухо на дырку: "Чё там Флаттер бормочет?"
channel?.setMessageHandler { message, reply ->
Log.d("Native", "Received from Flutter: $message") // Ага, пришло!
// И тут же пишем ответную записку и пихаем обратно
reply.reply("Hello from Android!")
}
}
}
И главное, чем он от других каналов отличается, а то все путаются:
- MethodChannel: Это когда ты как начальник: "Вась, выполни метод
getBatteryLevelи отчёт предоставь". Чётко, по протоколу. - EventChannel: Это как подписаться на паблик. Натив тебе стримит события: "Слушай, заряд упал", "Слушай, заряд упал ещё", "Ой, всё".
- BasicMessageChannel: А это просто два чувака, которые могут в любой момент крикнуть в дырку: "Э, кстати..." и перекинуться чем угодно — строкой, мапой, списком. Свободнее, блядь, но и ответственности больше. Сам договорённости придумывай, что в этих сообщениях будет.