Реализации плагина с использованием механизма 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
│ │ └── plugin.h
│ ├── CMakeLists.txt
│ └── plugin.cc
├── 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, 31 files
Структура проекта Flutter-разработчику должна быть знакома.
Исключением является директория <project>/aurora, в которой находится С++-код плагина
для взаимодействия с Flutter Embedder
и реализации общения с кодом плагина на Dart через Platform Channels:
CMakeLists.txt— сборка плагина реализована через CMake;plugin.h— содержит определениеPLUGIN_EXPORTи объявление точки входа — функции плагина;plugin.cc— реализация плагина.
В директории <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находится пример приложения, взаимодействующего с плагином.
Для начала необходимо изменить С++-части плагина.
В версии Flutter 3.35.7 имя приложения получается через класс cw::ApplicationWrapper,
объявленный в пакете aurora_client_wrapper.
В классе cw::PluginRegistrar доступен метод app() для получения cw::ApplicationWrapper.
В файле <project>/aurora/plugin.cc нужно заполнить обёртку cw::ApplicationWrapper,
заменить шаблонный метод onGetPlatformVersion на onGetApplicationName,
обновить список доступных методов
и вызвать метод cw::ApplicationWrapper::GetApplicationInfo() внутри метода onGetApplicationName:
...
namespace Methods {
- constexpr auto PlatformVersion = "getPlatformVersion";
+ constexpr auto ApplicationName = "applicationName";
}
class PlatformChannelsDemoPlugin final : public cw::BasicPlugin<> {
public:
explicit PlatformChannelsDemoPlugin(cw::PluginRegistrar* registrar);
private:
Result HandleMethodCall(const std::string& name, const cw::EncodableValue* arguments) final;
// Methods MethodCall
- cw::EncodableValue onGetPlatformVersion();
+ cw::EncodableValue onGetApplicationName(const cw::EncodableValue* arguments);
+ cw::ApplicationWrapper* app_;
};
PlatformChannelsDemoPlugin::PlatformChannelsDemoPlugin(cw::PluginRegistrar* registrar)
- : cw::BasicPlugin<>(Channels::Methods, registrar->messenger()) {}
+ : cw::BasicPlugin<>(Channels::Methods, registrar->messenger()), app_(registrar->app()) {}
- PlatformChannelsDemoPlugin::Result PlatformChannelsDemoPlugin::HandleMethodCall(const std::string& name, [[maybe_unused]] const cw::EncodableValue* arguments) {
+ PlatformChannelsDemoPlugin::Result PlatformChannelsDemoPlugin::HandleMethodCall(const std::string& name, const cw::EncodableValue* arguments) {
- if (name == Methods::PlatformVersion) {
- return onGetPlatformVersion();
+ if (name == Methods::ApplicationName) {
+ return onGetApplicationName(arguments);
}
return Result(cw::NotImplemented());
}
- cw::EncodableValue PlatformChannelsDemoPlugin::onGetPlatformVersion() {
- return "Aurora OS.";
- }
+ cw::EncodableValue PlatformChannelsDemoPlugin::onGetApplicationName(const cw::EncodableValue* arguments) {
+ // Получение имени приложения
+ const auto name = app_->GetApplicationInfo(cw::ApplicationWrapper::InfoType::Name);
+ if (arguments) {
+ // Получить префикс
+ const auto prefix = arguments->GetValue<std::string>("prefix");
+ if (prefix) {
+ // Вернуть данные с префиксом
+ return *prefix + name;
+ }
+ }
+ return name;
+ }
...
Доработка 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.
Нужно доработать его для вывода информации о названии приложения через плагин.
Для повышения читаемости кода, систематизации и упрощения написания приложений-примеров
был разработан плагин aurora_examples_common_lib.
Добавить в зависимости приложения-примера плагин aurora_examples_common_lib в pubspec.yaml можно
выполнив в папке example команду:
cd example
flutter-aurora pub add aurora_examples_common_lib
Либо отредактировав <plugin>/example/pubspec.yaml следующим образом:
dependencies:
...
aurora_examples_common_lib: ^2.1.1
Если список зависимостей редактировался вручную, то нужно обновить зависимости примера:
flutter-aurora pub get
Нужно доработать приложение, которое будет использовать плагин platform_channels_demo, демонстрировать название приложения
и прокидывать префикс (строку, предваряющую название) из Dart-кода в C++ и обратно:
import 'package:flutter/material.dart';
import 'package:aurora_examples_common_lib/list_item_data.dart';
import 'package:aurora_examples_common_lib/list_item_info.dart';
import 'package:aurora_examples_common_lib/list_separated.dart';
import 'package:aurora_examples_common_lib/theme/colors.dart';
import 'package:aurora_examples_common_lib/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 │
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘