Одной из самых больших проблем для мобильных кроссплатформенных сред является то, как добиться собственной производительности и как помочь разработчикам создавать различные виды функций для разных устройств и платформ с минимальными усилиями. При этом мы должны помнить, что UX должен оставаться таким же, но с уникальными компонентами, которые являются специфическими для каждой конкретной платформы (Android и iOS).
Хотя кроссплатформенные платформы (в большинстве случаев) могут решать задачи, специфичные для платформы, существует определенное количество задач, которые с помощью специального кода, специфичного для платформы, могут быть достигнуты только через native. Вопрос в том, как эти структуры могут установить связь между конкретной платформой и приложением? Лучшим примером является канал платформы Flutter .
Что такое канал платформы и когда мы должны его использовать?
По мере роста сообщества Flutter появляется все больше и больше подключаемых модулей и пакетов сообщества, которые выполняют функции, специфичные для платформы. Если вашему проекту требуется особая функция, которая не поддерживается во Flutter, или ее проще реализовать на собственной стороне, вам необходимо установить связь между собственными платформами (Android или iOS) и Flutter для выполнения этого пользовательского кода, специфичного для платформы.
Платформа Channel работает по принципу отправки и получения сообщений без генерации кода. Связь является двунаправленной и асинхронной. Приложение Flutter (часть приложения, написанная на Dart) в этом сообщении представляет клиента, который отправляет сообщения на хост (Android или iOS) и ожидает ответ, как успешный, так и неудачный.
Когда сообщение получено на стороне хоста, мы можем выполнить необходимую логику в собственном коде (Java / Kotlin для Android или Objective-C / Swift для iOS) или вызвать любые API для конкретной платформы и отправить ответ обратно в приложение Flutter. через канал. Когда каналы создаются, мы должны помнить о соглашениях об именах. Название канала в приложении Flutter должно совпадать с именем на нативной стороне.
Вам также может понравиться:
Учебник Flutter для разработчиков: пошаговое руководство по созданию приложений .
Настроить
Одной из основных характеристик Platform Channel является тот факт, что его легко настроить и понять как на стороне флаттера, так и на нативной стороне. Это также хорошо документировано и объяснено в официальной документации .
Чтобы объяснить, как настроить / создать канал, я приведу простой пример взаимодействия между приложением Flutter и нативным Android (Kotlin).
Во-первых, нам нужно создать канал в приложении Flutter с соответствующим именем. В этом случае мы можем назвать его «platform_channel»:
дротик
1
static const MethodChannel _channel = const MethodChannel('platform_channel');
Затем нам нужно создать канал на стороне Android с таким же именем:
Котлин
xxxxxxxxxx
1
companion object {
2
@JvmStatic
3
fun registerWith(registrar: Registrar) {
4
val channel = MethodChannel(registrar.messenger(), "platform_channel")
5
channel.setMethodCallHandler(PlatformChannelPlugin(registrar.activity()))
6
}
7
}
Как только мы создадим канал, нам нужно создать метод в нашем приложении Flutter в PlatformChannel
классе, который будет взаимодействовать с native:
дротик
xxxxxxxxxx
1
static Future<String> dummy_func() async {
2
String result = await _channel.invokeMethod('dummy_func');
3
return result;
4
}
Теперь, чтобы получить ответ от этой функции и от нативной, нам нужно добавить это в приложение Flutter, где мы хотим получить результат:
дротик
xxxxxxxxxx
1
static Future<String> getDummyFunc() async => await PlatformChannel.dummy_func();
Последний шаг — предоставить реализацию для dummy_func
в нативном:
Котлин
xxxxxxxxxx
1
override fun onMethodCall(call: MethodCall, result: Result) {
2
when {
3
call.method == "dummy_func" -> result.success(setupDummyFunc(call))
4
else -> result.notImplemented()
5
}
6
}
7
private fun setupDummyFunc(call: MethodCall): String {
9
return "return dummy string from native"
10
}
С помощью этого куска кода мы можем сказать, что установили базовую связь между приложением Flutter и нативным. Конечно, это можно расширить, чтобы обеспечить любую реализацию, которая нам нужна. Если мы хотим передать аргументы нативным функциям, мы можем создать Map
значения и передать их invokeMethod
в качестве второго параметра:
дротик
xxxxxxxxxx
1
Map<String, dynamic> args = <String, dynamic>{};
2
args.putIfAbsent("dummy1", () => “dummy1”);
3
args.putIfAbsent("dummy2", () => “dummy2”);
4
args.putIfAbsent("dummy3", () => “dummy3”);
дротик
xxxxxxxxxx
1
static Future<String> dummy_func() async {
2
String result = await _channel.invokeMethod(‘dummy_func’, args);
3
return result;
4
}
Теперь мы можем получить доступ к этим значениям на родном языке с помощью их идентификаторов:
Котлин
xxxxxxxxxx
1
dummy1 = call.argument<String>("dummy1").toString()
2
dummy2 = call.argument<String>("dummy2").toString()
3
dummy3 = call.argument<String>("dummy3").toString()
Здесь важно упомянуть, что, если мы планируем создать сложную связь между Dart и кодом, специфичным для платформы, которая предполагает использование сложных структур данных, я настоятельно рекомендую использовать некоторый механизм для сериализации структурированных данных. К счастью, Google предлагает простое решение для этого. Это называется протокол буфера .
Буферы протокола являются платформо-независимыми от языка механизмами для сериализации данных. Более того, Google предоставил учебные пособия по использованию буферов протокола для вашего языка.
Преимущества платформы канала
Когда мы имеем дело с любым общением, говорим ли мы об общении между двумя или более приложениями, об общении внутри одного приложения или, как в нашем случае, об общении с Dart и собственным кодом, возникает логичный вопрос: является ли это общение безопасным и надежны?
Платформа Channel Platform защищена, и это одно из важных преимуществ, которые предлагает Platform Channel. В нашем процессе есть буфер памяти для связи между Dart и собственным кодом, и для установления этой связи не требуется никакой межпроцессной связи; таким образом, ни один другой внешний процесс не может получить доступ к этой связи. Это означает, что Platform Channel имеет тот же уровень безопасности, что и любое другое собственное приложение для Android или iOS.
Одним из преимуществ Platform Channel является коммуникация, которая сама по себе является асинхронной и двунаправленной, то есть Platform Channel не блокирует выполнение других задач, которые не зависят от собственного кода. Как только нативный код завершит свою работу, результат будет передан в Dart, и будет вызван соответствующий обратный вызов, и наоборот.
Еще одним преимуществом является сериализация и десериализация значений в сообщениях и из них, что происходит автоматически при отправке и получении значений. Это представляет собой ценное преимущество Platform Channel наряду с возможностью использования протокольных буферов для сериализации структурированных данных.
Ограничения
В настоящее время метод канала может быть вызван только из потока пользовательского интерфейса (из основного изолята). Вызов MethodChannel
и EventChannel
от порожденного изолята в данный момент невозможен. Выполнение длительных операций в главном потоке может вызвать нежелательную работу приложения Flutter, и сторона платформы заблокирует другие каналы сообщений. Возможно, можно создать обходной путь для этого с портами, но лучший совет - избегать тяжелой работы с основным потоком, пока Flutter не разрешит проблемы, возникающие при вызове методов канала платформы из другого Isolate.
обзор
В целом, Platform Channel представляет собой способ соединения собственного кода с приложением Flutter (Dart). Он может быть использован для реализации любой отсутствующей функциональности Flutter с использованием кода для конкретной платформы (плагинов) и вызова любых API. Более того, он хорошо документирован и хорошо описан в официальной документации и продолжает оставаться удобным инструментом в кроссплатформенной разработке.