Реализации плагина с использованием механизма Platform Channels
Пример платформо-зависимого плагина, взаимодействующего с ОС Аврора через механизм Platform Channels. Задача плагина — получить название приложения с использованием Platform Channels.
Реализация плагина с использованием Platform Channels даёт максимальные возможности для реализации плагина.
Flutter Embedder реализует общий интерфейс Client Wrapper, который позволяет легко портировать плагины
на другие платформы.
Так же Flutter Embedder реализует методы специфичные для платформы,
которые можно получить через подключение заголовочного файла flutter_aurora.h.
Примечание:
Этот демонстрационный плагин доступен в репозитории Flutter в разделе examples/platform_channel.
Содержание:
Создание проекта
Плагин Platform Channels является платформо-зависимым,
то есть зависит от операционной системы.
Подробнее про типы плагинов можно ознакомиться в разделе Пакеты Flutter.
Platform Channels позволяет реализовать плагин, который обменивается данными через MethodChannel
или EventChannel.
с платформо-зависимой частью плагина из Dart-части плагина.
Platform Channels также даёт доступ к публичным методам Flutter Embedder.
Для генерации шаблона плагина можно выполнить следующую команду в терминале:
flutter-aurora create --template=plugin --platforms aurora --org=ru.aurora platform_channels_demo
ru.aurora— имя организации (Organization name), участвует в формировании названия пакета;platform_channels_demo— название плагина (Application Name), участвует в формировании названия пакета.
Данная команда генерирует базовый пример плагина Flutter с настроенным окружением для сборки под ОС Аврора. Структура файлов и каталогов проекта имеет следующий вид:
.
├── aurora
│ ├── include
│ │ └── platform_channels_demo
│ │ ├── globals.h
│ │ └── platform_channels_demo_plugin.h
│ ├── CMakeLists.txt
│ └── platform_channels_demo_plugin.cpp
├── example
│ ├── aurora
│ │ ├── desktop
│ │ │ └── ru.aurora.platform_channels_demo_example.desktop
│ │ ├── icons
│ │ │ ├── 108x108.png
│ │ │ ├── 128x128.png
│ │ │ ├── 172x172.png
│ │ │ └── 86x86.png
│ │ ├── rpm
│ │ │ └── ru.aurora.platform_channels_demo_example.spec
│ │ ├── CMakeLists.txt
│ │ └── main.cpp
│ ├── integration_test
│ │ └── plugin_integration_test.dart
│ ├── lib
│ │ └── main.dart
│ ├── test
│ │ └── widget_test.dart
│ ├── analysis_options.yaml
│ ├── platform_channels_demo_example.iml
│ ├── pubspec.lock
│ ├── pubspec.yaml
│ └── README.md
├── lib
│ ├── platform_channels_demo.dart
│ ├── platform_channels_demo_method_channel.dart
│ └── platform_channels_demo_platform_interface.dart
├── test
│ ├── platform_channels_demo_method_channel_test.dart
│ └── platform_channels_demo_test.dart
├── analysis_options.yaml
├── CHANGELOG.md
├── LICENSE
├── platform_channels_demo.iml
├── pubspec.lock
├── pubspec.yaml
└── README.md
14 directories, 32 files
Структура проекта Flutter-разработчику должна быть знакома.
Исключением является директория <project>/aurora, в которой находится С++-код плагина
для взаимодействия с Flutter Embedder
и реализации общения с кодом плагина на Dart через Platform Channels:
CMakeLists.txt— сборка плагина реализована через CMake;globals.h— содержит определениеPLUGIN_EXPORT;platform_channels_demo_plugin.h— заголовочный файл реализации плагина;platform_channels_demo_plugin.cpp— реализация плагина.
В директории <project>/example/aurora находятся файлы, обеспечивающие работу демо-приложения плагина на платформе ОС Аврора:
CMakeLists.txt— приложение и плагины Flutter для ОС Аврора имеют платформенную часть на С++, а сборка реализована через CMake;desktop/ru.aurora.app_demo.desktop— файл с конфигурацией ярлыка приложения. В нём можно указать название приложения, нужные права для приложения и другие настройки;icons/*.png— иконки приложения;main.cpp— точка входа в приложение для ОС Аврора. Это зачастую шаблонный код для запуска всех необходимых компонентов Flutter и приложения;rpm/ru.aurora.app_demo.spec— файл с конфигурацией установочного пакета, который утилита rpmbuild использует для сборки RPM-пакета.
Примечание:
Для предварительного знакомства с Flutter можно обратиться к документации Flutter и создать своё первое приложение, используя информацию из статьи "Write your first Flutter app".
Доработка С++-части
Плагин выполняет задачу по получению названия приложения через механизм Platform Channels.
Продемонстрирует обращение к функции Flutter Embedder и передачу данных через MethodChannel.
Модифицируем шаблон под эти задачи.
В корне плагина находится папка <project>/aurora, в ней лежит С++-код,
реализующий механизм Platform Channels плагина.
В папке lib лежит Dart-часть кода плагина.
В папке exampleнаходится пример приложения, взаимодействующего с плагином.
Для начала необходимо изменить С++-части плагина.
В директории <project>/aurora/include/platform_channels_demo находится заголовочный файл, в котором
нужно убрать шаблонный метод onGetPlatformVersion и заменить его на метод onGetApplicationName
для получения названия приложения:
// ...
// Методы MethodCall
EncodableValue onGetApplicationName(const MethodCall& call);
// ...
В файле <project>/aurora/platform_channels_demo_plugin.cpp нужно добавить реализацию:
// ...
namespace Methods {
constexpr auto ApplicationName = "applicationName";
} // пространство имён Methods
namespace Encodable {
template <typename T>
inline bool TypeIs(const EncodableValue val) {
return std::holds_alternative<T>(val);
}
template <typename T>
inline const T GetValue(EncodableValue val) {
return std::get<T>(val);
}
inline std::string GetString(const EncodableMap& map, const std::string& key) {
auto it = map.find(EncodableValue(key));
if (it != map.end() && TypeIs<std::string>(it->second))
return GetValue<std::string>(it->second);
return std::string();
}
} // пространство имён Encodable
// ...
EncodableValue PlatformChannelsDemoPlugin::onGetApplicationName(const MethodCall& call) {
if (Encodable::TypeIs<EncodableMap>(*call.arguments())) {
// Получить аргументы
const EncodableMap params = Encodable::GetValue<EncodableMap>(*call.arguments());
// Получить префикс
std::string prefix = Encodable::GetString(params, "prefix");
// Вернуть данные с префиксом
return prefix + aurora::GetApplicationName();
}
return aurora::GetApplicationName();
}
// ...
Класс MethodCall содержит данные, переданные из Dart-кода, которые можно получить в С++-части
плагина.
В этом методе есть пространство имен Encodable, содержащее вспомогательные методы,
облегчающие работу с данными.
В методе onGetApplicationName происходит вызов метода aurora::GetApplicationName(),
который реализован во Flutter Embedder.
Для корректной работы с публичными методами Flutter Embedder следует подключить заголовочный файл flutter_aurora.h:
#include <flutter/flutter_aurora.h>
Доработка Dart-части
Плагин взаимодействует с приложением через Dart-часть плагина. Все базовые элементы для такого плагина уже созданы по шаблону, а именно:
PlatformChannelsDemo— сам плагин, который подключается в приложение;PlatformChannelsDemoPlatform— интерфейс, который позволяет расширять плагин;MethodChannelPlatformChannelsDemo— реализация методов интерфейса плагина.
В Dart-части плагина необходимо изменить все файлы для реализации задачи — получения
названия приложения.
Для этого в файле <plugin>/lib/platform_channels_demo.dart нужно изменить класс PlatformChannelsDemo,
заменив шаблонный метод на необходимый getApplicationName:
class PlatformChannelsDemo {
Future<String?> getApplicationName({String? prefix}) {
return PlatformChannelsDemoPlatform.instance.getApplicationName(prefix);
}
}
В методе присутствует опциональный параметр prefix для демонстрации передачи данных с помощью Platform Channels.
В файле <plugin>/lib/platform_channels_demo_platform_interface.dart следует обновить методы
интерфейса:
Future<String?> getApplicationName(String? prefix) {
throw UnimplementedError('getApplicationName() has not been implemented.');
}
Остаётся последний этап — реализация метода и Platform Channels со стороны Dart.
Для этого файл <plugin>/lib/platform_channels_demo_method_channel.dart необходимо модифицировать
следующим образом:
// Ключи плагина канала платформы
const channelMethods = "platform_channels_demo";
// Методы плагина канала платформы
enum Methods {
applicationName,
}
/// Реализация [PlatformChannelsDemoPlatform], которая использует методы каналов.
class MethodChannelPlatformChannelsDemo extends PlatformChannelsDemoPlatform {
/// Метод канала, используемый для взаимодействия с собственной платформой.
@visibleForTesting
final methods = const MethodChannel(channelMethods);
@override
Future<String?> getApplicationName(String? prefix) async {
if (prefix == null) {
return await methods.invokeMethod<String>(Methods.applicationName.name);
} else {
return await methods.invokeMethod<String>(Methods.applicationName.name, {
'prefix': prefix,
});
}
}
}
Доработка примера
Шаблон Platform Channels плагина, генерируемый Flutter CLI, имеет приложение-пример для работы с
плагином в директории example.
Нужно доработать его для вывода информации о названии приложения через плагин.
Для повышения читаемости кода, систематизации и упрощения написания приложений-примеров
был разработан плагин internal_aurora.
Добавить в зависимость плагин internal_aurora в pubspec.yaml можно следующим образом:
dependencies:
internal_aurora:
git:
url: https://developer.auroraos.ru/git/flutter/flutter-community-plugins/internal_aurora.git
Обновить зависимости в директории example:
cd example
flutter-aurora pub get
Нужно доработать приложение, которое будет использовать плагин platform_channels_demo, демонстрировать название приложения
и прокидывать префикс (строку, предваряющую название) из Dart-кода в C++ и обратно:
import 'package:flutter/material.dart';
import 'package:internal_aurora/list_item_data.dart';
import 'package:internal_aurora/list_item_info.dart';
import 'package:internal_aurora/list_separated.dart';
import 'package:internal_aurora/theme/colors.dart';
import 'package:internal_aurora/theme/theme.dart';
import 'package:platform_channels_demo/platform_channels_demo.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final PlatformChannelsDemo _plugin = PlatformChannelsDemo();
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: internalTheme,
home: Scaffold(
appBar: AppBar(
title: const Text('Platform Channels Demo'),
),
body: ListSeparated(
children: [
const ListItemInfo("""
An example of a platform-dependent plugin that works with the
Aurora OS via the Platform Channels.
"""),
ListItemData(
'Application name',
InternalColors.purple,
description: 'Getting the application name through Platform Channels',
future: _plugin.getApplicationName(),
),
ListItemData(
'Application name & Prefix',
InternalColors.green,
description: 'Getting the application name and passing data through Platform Channels',
future: _plugin.getApplicationName(
prefix: 'Name: ',
),
),
],
),
),
);
}
}
Теперь можно запустить приложение. В корне проекта следует выполнить команду Flutter CLI для сборки приложения и получения установочного файла RPM.
В корне проекта выполнить команду Flutter CLI для сборки и запуска приложения:
flutter-aurora run
Примечание:
Для сборки доступны 3 архитектуры, более детально с этим вопросом можно ознакомиться в разделе "Целевая архитектура".
После успешной сборки можно наблюдать следующий вывод в терминале:
┌─ Result ─────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ ./build/aurora/psdk_5.0.0.60/aurora-x64/release/RPMS/ru.aurora.platform_channels_demo_example-0.1.0-1.x86_64.rpm │
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘