Что такое BasicMessageChannel в Flutter?

Ответ

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: А это просто два чувака, которые могут в любой момент крикнуть в дырку: "Э, кстати..." и перекинуться чем угодно — строкой, мапой, списком. Свободнее, блядь, но и ответственности больше. Сам договорённости придумывай, что в этих сообщениях будет.