diff --git a/README.md b/README.md index e246fa9..cfe77b3 100644 --- a/README.md +++ b/README.md @@ -1,60 +1,35 @@ -
- -
- # Плагины для ОС Аврора -Этот репозиторий содержит Flutter плагины для платформы ОС Аврора. Мы находимся в процессе создания необходимых плагинов для разработки всевозможных приложений пользователей. - -Если плагин который вы ищете еще не реализован для ОС Аврора оставьте свое сообщение в [issue](https://gitlab.com/omprussia/flutter/flutter-plugins/-/issues), либо рассмотрите возможность самостоятельной разработки плагина для развития Open Source сообщества ОС Аврора. Мы будем рады вашим мерж-реквестам! - -# Разработка плагина для ОС Аврора - -Подробно процесс создания платформозависимых плагинов описан в статье [«Flutter на ОС Аврора»](#todo). - -Если у вас имеются вопросы, присоединяйтесь к [сообществу](https://t.me/aurora_devs) ОС Аврора в Telegram канале, где вы сможете задать интересующий вас вопрос и следить за всеми актульными новостями. - -Для разработки платформозависимого плагина, необходимо использовать адаптированный под ОС Аврора [Flutter SDK](https://gitlab.com/omprussia/flutter/flutter). - -Ниже перечислены четыре вида плагинов, которые могут -применяться в ОС Аврора. - -- ### Dart Package - - Пакет написанный на языке Dart, например пакет [`path`](https://pub.dev/packages/path), расширяющий возможности Flutter, добавляя в него новые виджеты или функции, который не является платформозависимым. - -- ### Plugin Package - - Пакет, предоставляющий API на языке Dart в сочетании с одной или несколькими реализациями под конкретные платформы, использующий механизм [Platform Channels](https://docs.flutter.dev/platform-integration/platform-channels). - Для реализации плагина под ОС Аврора используется язык C++. +![preview.png](documentation/data/preview.png) -- ### Qt Plugin Package +Этот репозиторий содержит плагины Flutter для платформы ОС Аврора. Мы находимся в процессе создания необходимых плагинов для разработки всевозможных приложений пользователей. Если плагин который вы ищете еще не реализован для ОС Аврора оставьте сообщение в [issue](https://gitlab.com/omprussia/flutter/flutter-plugins/-/issues) либо рассмотрите возможность создать пакет самостоятельно. Мы будем рады вашим мерж-реквестам! - Пакет, аналогичный `Plugin Package`, но использующий в реализации под ОС Аврора библиотеку Qt. Данный вид пакета используется в случае, если системное API ОС Аврора, предоставляющее необходимую функциональность, использует библиотеку Qt. +## Разработка плагина для ОС Аврора - ОС Аврора старается минимизировать использование библиотеки Qt в Flutter плагинах, поэтому, если имеется возможность не использовать библиотеку Qt в реализации плагина под ОС Аврора, то лучше ее не использовать. +Что бы создать платформо-зависимый плагин воспользуйтесь [Flutter SDK](https://gitlab.com/omprussia/flutter/flutter) с поддержкой ОС Аврора. Для платформы Аврора доступно четыре варианта создания плагина, все они перечислены ниже с примерами: -- ### FFI Plugin Package +- [Dart package](documentation/dart_package.md); +- [Plugin package](documentation/plugin_package.md); +- [Qt plugin package](documentation/qt_plugin_package.md); +- [FFI Plugin package](documentation/ffi_plugin_package.md). - Пакет, предоставляющий API на языке Dart в сочетании с одной или несколькими реализациями под конкретные платформы, использующий механизм [Dart FFI](https://dart.dev/guides/libraries/c-interop). +Подробно процесс создания платформо-зависимых плагинов можно найти в статье "[Flutter на ОС Аврора](https://habr.com/ru/articles/761176/)". Если остаются вопросы присоединяйтесь к сообществу ОС Аврора "[Aurora Developers](https://t.me/aurora_devs)" в Telegram, там вы сможете задать вопрос по Flutter и следить за новостями. -# Демонстрационное приложение +## Демонстрационное приложение -Плагины из данного проекта объеденены в одно [общее приложение](./example), предназначеное для демонстрации работы реализованных и проверенных на ОС Аврора плагинов. +![preview.png](documentation/data/preview_app.png) -
- -
+Все плагины имеют общее демонстрационное приложение **Flutter example packages**. Оно предназначено для демонстрации работы как платформо-зависимых так и нет плагинов/пакетов. Выполняет роль единого приложения-примера для платформо-зависимых плагинов и позволяет проверить работоспособность не платформо зависимых плагинов на платформе ОС Аврора. -# Платформозависимые плагины Flutter +## Платформо-зависимые плагины Flutter -Список платформозависимых плагинов, реализованых под ОС Аврора, либо зависящих от платформозависимых плагинов. +Список платформо-зависимых плагинов созданных для ОС Аврора либо зависящих от платформо-зависимых плагинов ОС Аврора. | Плагин ОС Аврора | Версия | Внешний плагин | Версия | Версия ОС Аврора | |----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------|-------------------------------------------------------------------------------------|----------|--------------------| | [battery_plus_aurora](https://gitlab.com/omprussia/flutter/flutter-plugins/-/tree/master/packages/battery_plus/battery_plus_aurora) | `0.0.1` | [battery_plus](https://pub.dev/packages/battery_plus) | `4.0.1` | `4.0.2.269` | | [device_info_plus_aurora](https://gitlab.com/omprussia/flutter/flutter-plugins/-/tree/master/packages/device_info_plus/device_info_plus_aurora) | `0.0.1` | [device_info_plus](https://pub.dev/packages/device_info_plus) | `8.2.2` | `4.0.2.269` | -| [flutter_keyboard_visibility_aurora](https://gitlab.com/omprussia/flutter/flutter-plugins/-/tree/master/packages/flutter_keyboard_visibility/flutter_keyboard_visibility_aurora) | `0.0.1` | [flutter_keyboard_visibility](https://pub.dev/packages/flutter_keyboard_visibility) | `5.4.1` | `4.0.2.269` | +| [flutter_keyboard_visibility_aurora](https://gitlab.com/omprussia/flutter/flutter-plugins/-/tree/master/packages/flutter_keyboard_visibility/flutter_keyboard_visibility_aurora) | `0.0.1` | [flutter_keyboard_visibility](https://pub.dev/packages/flutter_keyboard_visibility) | `5.4.1` | `4.0.2.269` | | [flutter_local_notifications_aurora](https://gitlab.com/omprussia/flutter/flutter-plugins/-/tree/master/packages/flutter_local_notifications/flutter_local_notifications_aurora) | `0.0.1` | [flutter_local_notifications](https://pub.dev/packages/flutter_local_notifications) | `14.1.1` | `4.0.2.269` | | [flutter_secure_storage_aurora](https://gitlab.com/omprussia/flutter/flutter-plugins/-/tree/master/packages/flutter_secure_storage/flutter_secure_storage_aurora) | `0.0.1` | [flutter_secure_storage](https://pub.dev/packages/flutter_secure_storage) | `8.0.0` | `4.0.2.269` | | [package_info_plus_aurora](https://gitlab.com/omprussia/flutter/flutter-plugins/-/tree/master/packages/package_info_plus/package_info_plus_aurora) | `0.0.1` | [package_info_plus](https://pub.dev/packages/package_info_plus) | `3.1.2` | `4.0.2.269` | @@ -63,40 +38,35 @@ | [sqflite_aurora](https://gitlab.com/omprussia/flutter/flutter-plugins/-/tree/master/packages/sqflite/sqflite_aurora) | `0.0.1` | [sqflite](https://pub.dev/packages/sqflite) | `2.2.6` | `4.0.2.269` | | [wakelock_aurora](https://gitlab.com/omprussia/flutter/flutter-plugins/-/tree/master/packages/wakelock/wakelock_aurora) | `0.0.1` | [wakelock](https://pub.dev/packages/wakelock) | `0.6.2` | `4.0.2.269` | | [xdga_directories](https://gitlab.com/omprussia/flutter/flutter-plugins/-/tree/master/packages/xdga_directories) | `0.0.1` | - | - | `4.0.2.269` | -| - | - | [flutter_cache_manager](https://pub.dev/packages/flutter_cache_manager) | `3.3.0` | `4.0.2.269` | -| - | - | [cached_network_image](https://pub.dev/packages/cached_network_image) | `3.2.3` | `4.0.2.269` | -| - | - | [google_fonts](https://pub.dev/packages/google_fonts) | `4.0.4` | `4.0.2.269` | - -# Пакеты Flutter - -Список проверенных на совместимость c ОС Аврора пакетов, не являющихся платформозависимыми. - -| Внешний плагин | Версия | Версия ОС Аврора | -|-------------------------------------------------------------------------------------|----------|--------------------| -| [crypto](https://pub.dev/packages/crypto) | `3.0.2` | `4.0.2.269` | -| [cupertino_icons](https://pub.dev/packages/cupertino_icons) | `1.0.5` | `4.0.2.269` | -| [get_it](https://pub.dev/packages/get_it) | `7.6.0` | `4.0.2.269` | -| [intl](https://pub.dev/packages/intl) | `0.17.0` | `4.0.2.269` | -| [photo_view](https://pub.dev/packages/photo_view) | `0.14.0` | `4.0.2.269` | -| [scoped_model](https://pub.dev/packages/scoped_model) | `2.0.0` | `4.0.2.269` | -| [dartz](https://pub.dev/packages/dartz) | `0.10.1` | `4.0.2.269` | -| [freezed](https://pub.dev/packages/freezed) | `2.3.3` | `4.0.2.269` | -| [equatable](https://pub.dev/packages/equatable) | `2.0.5` | `4.0.2.269` | -| [flutter_markdown](https://pub.dev/packages/flutter_markdown) | `0.6.15` | `4.0.2.269` | -| [build_runner](https://pub.dev/packages/build_runner) | `2.3.3` | `4.0.2.269` | -| [freezed_annotation](https://pub.dev/packages/freezed_annotation) | `2.2.0` | `4.0.2.269` | -| [json_annotation](https://pub.dev/packages/json_annotation) | `4.8.0` | `4.0.2.269` | -| [json_serializable](https://pub.dev/packages/json_serializable) | `6.6.1` | `4.0.2.269` | -| [provider](https://pub.dev/packages/provider) | `6.0.5` | `4.0.2.269` | -| [qr_flutter](https://pub.dev/packages/qr_flutter) | `4.0.0` | `4.0.2.269` | -| [rxdart](https://pub.dev/packages/rxdart) | `0.27.7` | `4.0.2.269` | -| [translator](https://pub.dev/packages/translator) | `0.1.7` | `4.0.2.269` | - -# Вклад сообщества - -Этот проект поддерживается сообществом. Оставляйте ваши вопросы и отзывы в [issues](https://gitlab.com/omprussia/flutter/flutter-plugins/-/issues) проекта, -либо публикуйте ваши наработки в репозиторий через [merge request](https://gitlab.com/omprussia/flutter/flutter-plugins/-/merge_requests). - -Помните, что [демонстрационное приложение](./example) содержит не только сложные платформозависимые плагины, но и обычные пакеты, поэтому мы будем рады, если вы проверите ваши любимые Flutter пакеты на работоспособность в ОС Аврора и поделитесь вашими наработками с сообществом. - -Мы будем рады любому вашему вкладу в развитие проекта. +| - | - | [flutter_cache_manager](https://pub.dev/packages/flutter_cache_manager) | 3.3.0 | `4.0.2.269` | +| - | - | [cached_network_image](https://pub.dev/packages/cached_network_image) | 3.2.3 | `4.0.2.269` | +| - | - | [google_fonts](https://pub.dev/packages/google_fonts) | 4.0.4 | `4.0.2.269` | + +## Пакеты Flutter + +Список проверенных на совместимость и работоспособность в ОС Аврора пакетов Flutter не являющиеся платформо-зависимыми. + +| Внешний плагин | Версия | Версия ОС Аврора | +|-------------------------------------------------------------------------------------|---------|--------------------| +| [crypto](https://pub.dev/packages/crypto) | 3.0.2 | `4.0.2.269` | +| [cupertino_icons](https://pub.dev/packages/cupertino_icons) | 1.0.5 | `4.0.2.269` | +| [get_it](https://pub.dev/packages/get_it) | 7.6.0 | `4.0.2.269` | +| [intl](https://pub.dev/packages/intl) | 0.17.0 | `4.0.2.269` | +| [photo_view](https://pub.dev/packages/photo_view) | 0.14.0 | `4.0.2.269` | +| [scoped_model](https://pub.dev/packages/scoped_model) | 2.0.0 | `4.0.2.269` | +| [dartz](https://pub.dev/packages/dartz) | 0.10.1 | `4.0.2.269` | +| [freezed](https://pub.dev/packages/freezed) | 2.3.3 | `4.0.2.269` | +| [equatable](https://pub.dev/packages/equatable) | 2.0.5 | `4.0.2.269` | +| [flutter_markdown](https://pub.dev/packages/flutter_markdown) | 0.6.15 | `4.0.2.269` | +| [build_runner](https://pub.dev/packages/build_runner) | 2.3.3 | `4.0.2.269` | +| [freezed_annotation](https://pub.dev/packages/freezed_annotation) | 2.2.0 | `4.0.2.269` | +| [json_annotation](https://pub.dev/packages/json_annotation) | 4.8.0 | `4.0.2.269` | +| [json_serializable](https://pub.dev/packages/json_serializable) | 6.6.1 | `4.0.2.269` | +| [provider](https://pub.dev/packages/provider) | 6.0.5 | `4.0.2.269` | +| [qr_flutter](https://pub.dev/packages/qr_flutter) | 4.0.0 | `4.0.2.269` | +| [rxdart](https://pub.dev/packages/rxdart) | 0.27.7 | `4.0.2.269` | +| [translator](https://pub.dev/packages/translator) | 0.1.7 | `4.0.2.269` | + +## Вклад + +Этот проект поддерживается сообществом, и мы будем рады вашему вкладу и активности, оставляйте ваши вопросы, отзывы в [issue](https://gitlab.com/omprussia/flutter/flutter-plugins/-/issues) либо вашу работу в [мерж-реквесты](https://gitlab.com/omprussia/flutter/flutter-plugins/-/merge_requests). Помните что **Flutter example packages** содержит не только сложные платформо-зависимые плагины, мы будем рады вкладу в проверку на работоспособность платформо не зависимых плагинов. diff --git a/data/preview.png b/data/preview.png deleted file mode 100644 index 4a63ba8..0000000 Binary files a/data/preview.png and /dev/null differ diff --git a/data/preview_app.png b/data/preview_app.png deleted file mode 100644 index b0e4405..0000000 Binary files a/data/preview_app.png and /dev/null differ diff --git a/documentation/dart_package.md b/documentation/dart_package.md new file mode 100644 index 0000000..e9c7472 --- /dev/null +++ b/documentation/dart_package.md @@ -0,0 +1,119 @@ +# Dart package + +Пакеты написанные на Dart, например package [`path`](https://pub.dev/packages/path). Они могут содержать специфичные для Flutter функции и иметь зависимость от инфраструктуры Flutter, ограничивая их использование только Flutter, например package [`fluro`](https://pub.dev/packages/fluro). + +> Для демонстрации создания платформо-зависимого пакета для ОС Аврора типа "Dart package" был написан и опубликован проект "[Demo Dart Packages](https://gitlab.com/omprussia/flutter/demo-dart-packages)" которые подробно описан в статье "[Flutter на ОС Аврора](https://habr.com/ru/articles/761176/)". + +Проект "[Demo Dart Packages](https://gitlab.com/omprussia/flutter/demo-dart-packages)" содержит в себе пакет реализующий платформо-зависимый пакет для ОС Аврора типа "Dart package". Вообще этот тип пакета может быть как платформо-зависимым так и нет. Пакет "[Flutter Device](https://gitlab.com/omprussia/flutter/demo-dart-packages/-/tree/master/packages/aurora/dart_package_device?ref_type=heads)" из проекта [Demo Dart Packages](https://gitlab.com/omprussia/flutter/demo-dart-packages) становится платформо-зависимым использую [D-Bus](https://www.freedesktop.org/wiki/Software/dbus/) ОС Аврора. Данный пакет использует API ОС Аврора - "[Device Info API](https://developer.auroraos.ru/doc/software_development/reference/device_info)". + +Пакет Dart в минимальном виде состоит из файла [`pubspec.yaml`](https://dart.dev/tools/pub/pubspec), папки `lib` с как минимум одним файлом `.dart`. Создать пакет можно командой: + +```shell +$ flutter-aurora create --template=package +``` + +Рассмотрим пакет "[dart_package_device](https://gitlab.com/omprussia/flutter/demo-dart-packages/-/tree/master/packages/aurora/dart_package_device?ref_type=heads)" из проекта [Demo Dart Packages](https://gitlab.com/omprussia/flutter/demo-dart-packages). **dart_package_device** - платформо-зависимая реализация плагина "Flutter Device" для ОС Аврора типа "Dart package". В основе пакета лежит пакет `dbus` - нативная клиентская реализация D-Bus для Dart. С его помощью можно реализовать пакет Dart для ОС Аврора, ни строчки не написав на C++. + +Структура пакета **dart_package_device**: + +```shell +└── aurora + └── dart_package_device +    ├── lib +    │   ├── dart_package_device.dart +    │   └── ru_omp_device_info_features.dart +    ├── ru.omp.deviceinfo.Features.xml +    └── pubspec.yaml +``` + +Пакет `dbus` позволяет на основе xml-файла с интерфейсом D-Bus генерировать Dart-класс, который позволит выполнить доступные методы. + +Файл `packages/aurora/dart_package_device/ru.omp.deviceinfo.Features.xml` + +```xml + + + + + + + + +``` + +Выполнить генерацию можно командой: + +```shell +$ dart-dbus generate-remote-object ./ru.omp.deviceinfo.Features.xml \ +-o lib/ru_omp_device_info_features.dart +``` + +Результат генерации c файла `ru.omp.deviceinfo.Features.xml` следует рассматривать, как отправную точку для реализации. + +Файл `packages/aurora/dart_package_device/lib/ru_omp_device_info_features.dart` + +```dart +class RuOmpDeviceinfoFeatures extends DBusRemoteObject { + RuOmpDeviceinfoFeatures( + DBusClient client, String destination, DBusObjectPath path) + : super(client, name: destination, path: path); + + /// Вызов ru.omp.deviceinfo.Features.getDeviceModel() + Future callGetDeviceModel( + {bool noAutoStart = false, + bool allowInteractiveAuthorization = false}) async { + var result = await callMethod( + 'ru.omp.deviceinfo.Features', 'getDeviceModel', [], + replySignature: DBusSignature('s'), + noAutoStart: noAutoStart, + allowInteractiveAuthorization: allowInteractiveAuthorization); + return result.returnValues[0].asString(); + } +} +``` + +Теперь можно реализовать интерфейс **[device_platform_interface](https://gitlab.com/omprussia/flutter/demo-dart-packages/-/tree/master/device_platform_interface?ref_type=heads)** и в методе `registerWith` указать пакет **dart_package_device**, как платформо-зависимый плагин. + +Файл `packages/aurora/dart_package_device/lib/dart_package_device.dart` + +```dart +/// Метод, который выполнится при старте приложения +/// В этом методе можно установить платформо-зависимый плагин +static void registerWith() { + DevicePlatform.instance = DartPackageDevice(); +} + +/// Реализация метода интерфейса [DevicePlatform] +@override +Future get deviceName async { + // Инициализация клиента D-Bus + final client = DBusClient.session(); + + // Инициализация объекта + final features = RuOmpDeviceinfoFeatures( + client, + 'ru.omp.deviceinfo', + DBusObjectPath('/ru/omp/deviceinfo/Features'), + ); + + // Выполнение метода + final deviceName = await features.callGetDeviceModel(); + + // Закрытие клиента D-Bus + await client.close(); + + // Возвращение результата + return deviceName == '' ? null : deviceName; +} +``` + +В `pubspec.yaml` плагина **dart_package_device** следует указать `dartPluginClass` для того, чтобы с помощью метода `registerWith` прошла регистрация плагина в `общем-плагине` **flutter_device** при старте приложения. + +```yaml +flutter: + plugin: + platforms: + aurora: + dartPluginClass: DartPackageDevice +``` \ No newline at end of file diff --git a/documentation/data/preview.png b/documentation/data/preview.png new file mode 100644 index 0000000..04e20a1 Binary files /dev/null and b/documentation/data/preview.png differ diff --git a/documentation/data/preview_app.png b/documentation/data/preview_app.png new file mode 100644 index 0000000..79d1794 Binary files /dev/null and b/documentation/data/preview_app.png differ diff --git a/documentation/ffi_plugin_package.md b/documentation/ffi_plugin_package.md new file mode 100644 index 0000000..64e33dc --- /dev/null +++ b/documentation/ffi_plugin_package.md @@ -0,0 +1,185 @@ +# FFI Plugin package + +Специализированный пакет Dart, содержащий API, написанный на Dart, с одной или несколькими реализациями для конкретной платформы, использующими [Dart FFI](https://dart.dev/guides/libraries/c-interop). + +> Для демонстрации создания платформо-зависимого плагина для ОС Аврора типа "FFI Plugin package" был написан и опубликован проект "[Demo Dart Packages](https://gitlab.com/omprussia/flutter/demo-dart-packages)" которые подробно описан в статье "[Flutter на ОС Аврора](https://habr.com/ru/articles/761176/)". + +Проект "[Demo Dart Packages](https://gitlab.com/omprussia/flutter/demo-dart-packages)" содержит в себе пакет реализующий платформо-зависимый плагин для ОС Аврора типа "FFI Plugin package". Данный пакет использует API ОС Аврора - "[Device Info API](https://developer.auroraos.ru/doc/software_development/reference/device_info)". Плагин использует [QtDBus](https://doc.qt.io/qt-5/qtdbus-index.html) но не является типом плагина "Qt plugin package" так как не использует сигналы и слоты. + +Создать пакет "FFI Plugin package" можно командой: + +```shell +$ flutter-aurora create --template=plugin_ffi +``` + +Рассмотрим плагин "[ffi_plugin_device](https://gitlab.com/omprussia/flutter/demo-dart-packages/-/tree/master/packages/aurora/ffi_plugin_device?ref_type=heads)" из проекта [Demo Dart Packages](https://gitlab.com/omprussia/flutter/demo-dart-packages). **ffi_plugin_device** - платформо-зависимая реализация плагина "Flutter Device" для ОС Аврора типа "FFI Plugin package". + +Структура пакета **ffi_plugin_device** + +```shell +└── aurora + └── ffi_plugin_device +    ├── aurora +    │   └── CMakeLists.txt +    ├── ffigen.yaml +    ├── lib +    │   ├── ffi_plugin_device_bindings_generated.dart +    │   └── ffi_plugin_device.dart +    ├── pubspec.yaml +    └── src +    ├── CMakeLists.txt +    ├── ffi_plugin_device.cpp +    └── ffi_plugin_device.h +``` + +Для генерации привязок FFI можно использовать плагин [`ffigen`](https://pub.dev/packages/ffigen). Пакет, предоставляющий утилиты для работы с кодом интерфейса внешних функций, называется [`ffi`](https://pub.dev/packages/ffi). В `pubspec.yaml` плагина нужно добавить зависимости и активировать `ffiPlugin` для платформы ОС Аврора. + +```yaml +dependencies: + ffi: ^2.0.2 + +dev_dependencies: + ffigen: ^7.2.7 + +flutter: + plugin: + platforms: + aurora: + ffiPlugin: true + dartPluginClass: FFIPluginDevice +``` + +Для генерации привязок нужно добавить файл `ffigen.yaml` в корень плагина. + +Файл `packages/aurora/ffi_plugin_device/ffigen.yaml` + +```yaml +name: PluginDeviceBindings +llvm-path: + - '/usr/lib/llvm-14/lib/libclang.so' # Ubuntu 22.04 + - '/usr/lib/llvm-15/lib/libclang.so' # Ubuntu 23.04 +description: | + Bindings for `src/ffi_plugin_device.h`. +output: 'lib/ffi_plugin_device_bindings_generated.dart' +headers: + entry-points: + - 'src/ffi_plugin_device.h' + include-directives: + - 'src/ffi_plugin_device.h' +comments: + style: any + length: full +``` + +В файле `ffigen.yaml` указываются хедеры нужных библиотек. В данном случае библиотека лежит в папке `src`, которая получает название модели устройства с помощью [`Qt D-Bus`](https://doc.qt.io/qt-5/qtdbus-index.html). + +Файл `packages/aurora/ffi_plugin_device/src/ffi_plugin_device.h` + +```cpp +#ifdef __cplusplus +extern "C" { +#endif + +char *getDeviceName(); + +#ifdef __cplusplus +} +#endif +``` + +Файл `packages/aurora/ffi_plugin_device/src/ffi_plugin_device.cpp` + +```cpp +#include +#include + +#include "ffi_plugin_device.h" + +char *getDeviceName() +{ + QString deviceName = ""; + if (QDBusConnection::sessionBus().isConnected()) { + QDBusInterface iface("ru.omp.deviceinfo", + "/ru/omp/deviceinfo/Features", + "", + QDBusConnection::sessionBus() + ); + if (iface.isValid()) { + QDBusReply reply = iface.call("getDeviceModel"); + if (reply.isValid()) { + deviceName = reply.value(); + } + } + } + return deviceName.toUtf8().data(); +} +``` + +Выполнить генерацию FFI-привязок можно следующей командой, выполнив её из корня плагина (например, `packages/aurora/ffi_plugin_device`): + +```shell +flutter-aurora pub run ffigen --config ffigen.yaml +``` + +В папке `lib` будет сгенерирован файл `ffi_plugin_device_bindings_generated.dart`. + +Файл `packages/aurora/ffi_plugin_device/lib/ffi_plugin_device_bindings_generated.dart` + +```dart +import 'dart:ffi' as ffi; + +/// Bindings for `src/ffi_plugin_device.h`. +class PluginDeviceBindings { + /// Holds the symbol lookup function. + final ffi.Pointer Function(String symbolName) + _lookup; + + /// The symbols are looked up in [dynamicLibrary]. + PluginDeviceBindings(ffi.DynamicLibrary dynamicLibrary) + : _lookup = dynamicLibrary.lookup; + + /// The symbols are looked up with [lookup]. + PluginDeviceBindings.fromLookup( + ffi.Pointer Function(String symbolName) + lookup) + : _lookup = lookup; + + ffi.Pointer getDeviceName() { + return _getDeviceName(); + } + + late final _getDeviceNamePtr = + _lookup Function()>>( + 'getDeviceName'); + late final _getDeviceName = + _getDeviceNamePtr.asFunction Function()>(); +} +``` + +Теперь можно создать класс `FFIPluginDevice`, реализующий интерфейс **[device_platform_interface](https://gitlab.com/omprussia/flutter/demo-dart-packages/-/tree/master/device_platform_interface?ref_type=heads)**. + +Файл `packages/aurora/ffi_plugin_device/lib/ffi_plugin_device.dart` + +```dart +class FFIPluginDevice extends DevicePlatform { + /// Метод, который выполнится при старте приложения + /// В этом методе можно установить платформо-зависимый плагин + static void registerWith() { + DevicePlatform.instance = FFIPluginDevice(); + } + + /// Привязки к нативным функциям в [_dylib]. + final PluginDeviceBindings _bindings = PluginDeviceBindings( + DynamicLibrary.open('libffi_plugin_device.so'), + ); + + /// Реализация метода интерфейса [DevicePlatform] + @override + Future get deviceName async { + // Получение deviceName + final deviceName = _bindings.getDeviceName().cast().toDartString(); + // Возврат результата + return deviceName == '' ? null : deviceName; + } +} +``` \ No newline at end of file diff --git a/documentation/plugin_package.md b/documentation/plugin_package.md new file mode 100644 index 0000000..60316c2 --- /dev/null +++ b/documentation/plugin_package.md @@ -0,0 +1,166 @@ +# Plugin package + +Специализированный пакет Dart, содержащий API, написанный на Dart, в сочетании с одной или несколькими реализациями для конкретной платформы. Пакеты плагинов могут быть написаны для Android (с использованием Kotlin или Java), ОС Аврора (с использование С++), iOS (с использованием Swift или Objective-C), Интернета, macOS, Windows или Linux или любой их комбинации. + +> Для демонстрации создания платформо-зависимого пакета для ОС Аврора типа "Plugin package" был написан и опубликован проект "[Demo Dart Packages](https://gitlab.com/omprussia/flutter/demo-dart-packages)" которые подробно описан в статье "[Flutter на ОС Аврора](https://habr.com/ru/articles/761176/)". + +Проект "[Demo Dart Packages](https://gitlab.com/omprussia/flutter/demo-dart-packages)" содержит в себе пакет реализующий платформо-зависимый плагин для ОС Аврора типа "Plugin package". Данный пакет использует API ОС Аврора - "[Device Info API](https://developer.auroraos.ru/doc/software_development/reference/device_info)". Плагин использует [QtDBus](https://doc.qt.io/qt-5/qtdbus-index.html) но не является типом плагина "Qt plugin package" так как не использует сигналы и слоты. + +Создать пакет "Plugin package" можно командой: + +```shell +$ flutter-aurora create --template=plugin +``` + +Рассмотрим плагин "[plugin_device](https://gitlab.com/omprussia/flutter/demo-dart-packages/-/tree/master/packages/aurora/plugin_device?ref_type=heads)" из проекта [Demo Dart Packages](https://gitlab.com/omprussia/flutter/demo-dart-packages). **plugin_device** - платформо-зависимая реализация плагина "Flutter Device" для ОС Аврора типа "Plugin package". + +Структура пакета **plugin_device**: + +```shell +└── aurora + └── plugin_device + ├── aurora + │   ├── CMakeLists.txt + │   ├── include + │   │   └── plugin_device + │   │   └── plugin_device_plugin.h + │   └── plugin_device_plugin.cpp + ├── lib + │   ├── plugin_device.dart + │   └── plugin_device_method_channel.dart + └── pubspec.yaml +``` + +В `pubspec.yaml` плагина **plugin_device** нужно указать `pluginClass` и `dartPluginClass`. + +```yaml +flutter: + plugin: + platforms: + aurora: + pluginClass: PluginDevicePlugin + dartPluginClass: PluginDevice +``` + +`PluginDevicePlugin` - C++ класс реализующий `PluginInterface` пакета `flutter-embedder`. + +Файл `packages/aurora/plugin_device/aurora/include/plugin_device/plugin_device_plugin.h` + +```cpp +#include +#include + +class PLUGIN_EXPORT PluginDevicePlugin final : public PluginInterface +{ +public: + void RegisterWithRegistrar(PluginRegistrar ®istrar) override; + +private: + void onMethodCall(const MethodCall &call); + void onGetDeviceName(const MethodCall &call); + void unimplemented(const MethodCall &call); +}; +``` + +Файл `packages/aurora/plugin_device/aurora/plugin_device_plugin.cpp` + +```cpp +#include +#include +#include + +/** + * Регистрация [MethodChannel]. + */ +void PluginDevicePlugin::RegisterWithRegistrar(PluginRegistrar ®istrar) +{ + registrar.RegisterMethodChannel("plugin_device", + MethodCodecType::Standard, + [this](const MethodCall &call) { this->onMethodCall(call); }); +} + +/** + * Метод onMethodCall будет выполняться при вызове MethodChannel из Dart-плагина. + * По названию, передаваемому из плагина, можно вызвать нужный платформо-зависимый метод. + */ +void PluginDevicePlugin::onMethodCall(const MethodCall &call) +{ + const auto &method = call.GetMethod(); + if (method == "getDeviceName") { + onGetDeviceName(call); + return; + } + unimplemented(call); +} + +/** + * Платформо-зависимый метод, получающий название устройства + */ +void PluginDevicePlugin::onGetDeviceName(const MethodCall &call) +{ + if (!QDBusConnection::sessionBus().isConnected()) { + call.SendSuccessResponse(nullptr); + return; + } + QDBusInterface iface("ru.omp.deviceinfo", + "/ru/omp/deviceinfo/Features", + "", + QDBusConnection::sessionBus() + ); + if (iface.isValid()) { + QDBusReply reply = iface.call("getDeviceModel"); + if (reply.isValid()) { + call.SendSuccessResponse(reply.value().toStdString()); + return; + } + } + call.SendSuccessResponse(nullptr); +} + +/** + * Метод возвращающий [nullptr], если запрашиваемый метод не найден + */ +void PluginDevicePlugin::unimplemented(const MethodCall &call) +{ + call.SendSuccessResponse(nullptr); +} +``` + +`PluginDevice` - Dart-класс, реализующий **[device_platform_interface](https://gitlab.com/omprussia/flutter/demo-dart-packages/-/tree/master/device_platform_interface?ref_type=heads)** и устанавливающий при выполнении метода `registerWith` нужный экземпляр для взаимодействия с платформо-зависимой частью плагина. + +Файл `packages/aurora/plugin_device/lib/plugin_device.dart` + +```dart +class PluginDevice extends DevicePlatform { + /// Метод, который выполнится при старте приложения + /// В этом методе можно установить платформо-зависимый плагин + static void registerWith() { + DevicePlatform.instance = MethodChannelPluginDevice(); + } + + /// Реализация метода интерфейса [DevicePlatform] + @override + Future get deviceName => DevicePlatform.instance.deviceName; +} +``` + +[MethodChannel](https://api.flutter.dev/flutter/services/MethodChannel-class.html) класс плагина отличается от подобного класса для Android только названием и ключом для взаимодействия с платформо-зависимой частью. + +Файл `packages/aurora/plugin_device/lib/plugin_device_method_channel.dart` + +```dart +/// Реализация [PluginDevicePlatform], которая использует каналы методов +class MethodChannelPluginDevice extends DevicePlatform { + /// Канал метода, используемый для взаимодействия с собственной платформой + @visibleForTesting + final methodChannel = const MethodChannel('plugin_device'); + + /// Реализация метода получения названия устройства + /// getDeviceName - название метода, который можно проверить + /// в платформо-зависимой части плагина + @override + Future get deviceName async { + return await methodChannel.invokeMethod('getDeviceName'); + } +} +``` \ No newline at end of file diff --git a/documentation/qt_plugin_package.md b/documentation/qt_plugin_package.md new file mode 100644 index 0000000..4c853c9 --- /dev/null +++ b/documentation/qt_plugin_package.md @@ -0,0 +1,123 @@ +# Qt plugin package + +Qt plugin package - является обычным плагином типа "[Plugin package](#todo)", но использующего Qt сигналы и слоты. Проект "[Demo Dart Packages](https://gitlab.com/omprussia/flutter/demo-dart-packages)" содержит в себе пакет реализующий платформо-зависимый плагин для ОС Аврора типа "Plugin package", на его примере покажем как подключить сигналы и слоты к плагину. + +Плагин уже имеет в зависимостях Qt, но в нем не будут работать сигналы и слоты. Для их подключения следует добавить зависимости в класс реализующий `PluginInterface`: + +Файл `packages/aurora/plugin_device/aurora/include/plugin_device/plugin_device_plugin.h` + +```cpp +#include +#include + +#include + +class PLUGIN_EXPORT PluginDevicePlugin final + : public QObject, + public PluginInterface +{ + Q_OBJECT + +public: + void RegisterWithRegistrar(PluginRegistrar ®istrar) override; + +private: + void onMethodCall(const MethodCall &call); + void onGetDeviceName(const MethodCall &call); + void unimplemented(const MethodCall &call); +}; +``` + +А в файл реализации добавить в низ файла `#include "moc_sensors_plus_aurora_plugin.cpp"`: + +Файл `packages/aurora/plugin_device/aurora/plugin_device_plugin.cpp` + +```cpp +#include +#include +#include + +/** + * Регистрация [MethodChannel]. + */ +void PluginDevicePlugin::RegisterWithRegistrar(PluginRegistrar ®istrar) +{ + registrar.RegisterMethodChannel("plugin_device", + MethodCodecType::Standard, + [this](const MethodCall &call) { this->onMethodCall(call); }); +} + +/** + * Метод onMethodCall будет выполняться при вызове MethodChannel из Dart-плагина. + * По названию, передаваемому из плагина, можно вызвать нужный платформо-зависимый метод. + */ +void PluginDevicePlugin::onMethodCall(const MethodCall &call) +{ + const auto &method = call.GetMethod(); + if (method == "getDeviceName") { + onGetDeviceName(call); + return; + } + unimplemented(call); +} + +/** + * Платформо-зависимый метод, получающий название устройства + */ +void PluginDevicePlugin::onGetDeviceName(const MethodCall &call) +{ + if (!QDBusConnection::sessionBus().isConnected()) { + call.SendSuccessResponse(nullptr); + return; + } + QDBusInterface iface("ru.omp.deviceinfo", + "/ru/omp/deviceinfo/Features", + "", + QDBusConnection::sessionBus() + ); + if (iface.isValid()) { + QDBusReply reply = iface.call("getDeviceModel"); + if (reply.isValid()) { + call.SendSuccessResponse(reply.value().toStdString()); + return; + } + } + call.SendSuccessResponse(nullptr); +} + +/** + * Метод возвращающий [nullptr], если запрашиваемый метод не найден + */ +void PluginDevicePlugin::unimplemented(const MethodCall &call) +{ + call.SendSuccessResponse(nullptr); +} + +#include "moc_sensors_plus_aurora_plugin.cpp" +``` + +И для того что бы мок файл сгенерировался добавим в [set_target_properties](https://cmake.org/cmake/help/latest/command/set_target_properties.html) `AUTOMOC ON`: + +Файл `packages/aurora/plugin_device/aurora/CMakeLists.txt` + +``` +set_target_properties(${PLUGIN_NAME} PROPERTIES CXX_VISIBILITY_PRESET hidden AUTOMOC ON) +``` + +Для работы плагина в приложении Qt нужно включить отдельно. Сделать это можно добавив в `main` функцию приложения вызов метода `EnableQtCompatibility()`. Выглядеть это может следующим образом: + +```cpp +#include +#include +#include "generated_plugin_registrant.h" + +int main(int argc, char *argv[]) { + Application::Initialize(argc, argv); + EnableQtCompatibility(); // Включение "Qt plugin package" плагинов + RegisterPlugins(); + Application::Launch(); + return 0; +} +``` + +Добавив зависимости в плагин начнут работать сигналы и слоты Qt. ОС Аврора очень зависит от Qt, во Flutter мы стараемся минимизировать эту зависимость. Если есть возможность выбора типа для реализации платформо-зависимого плагина использование Qt нежелательно. \ No newline at end of file diff --git a/example/app_run.sh b/example/app_run.sh new file mode 100755 index 0000000..8f8a72b --- /dev/null +++ b/example/app_run.sh @@ -0,0 +1,98 @@ +#!/bin/bash + +# Copyright (c) 2023. Open Mobile Platform LLC. +# License: Proprietary. + +## Build example, sign rpm, upload/install/run rpm to device + +## Usage +## +## chmod +x ./run.sh +## +## ./run.sh \ +## -d : \ +## -s /home/user/sign/folder +## -p ru.auroraos.flutter_example_packages + +sudo echo 'Run...'; + +## Flutter path +FLUTTER="$HOME/.local/opt/flutter/bin/flutter" + +## https://developer.auroraos.ru/doc/software_development/psdk/setup +## Install Platform SDK path +## You may not have set the PSDK_DIR environment variable. +## export PSDK_DIR=$HOME/AuroraPlatformSDK/sdks/aurora_psdk + +while getopts d:s:p: flag; do + case "${flag}" in + d) device=${OPTARG} ;; + s) sign=${OPTARG} ;; + p) package=${OPTARG} ;; + *) + echo "usage: $0 [-d] [-s] [-p]" >&2 + exit 1 + ;; + esac +done + +if [ -z "$package" ]; then + echo "Specify package" + exit 1; +fi + +## Update dependency +$FLUTTER pub get + +## Generate internationalizing +$FLUTTER pub run build_runner build --delete-conflicting-outputs + +## Build aurora example app +{ + $FLUTTER build aurora --release +} || { + exit 1; +} + +if [ -n "$sign" ]; then + + key=$(ls "$sign"/*key.pem) + + if [ -z "$key" ]; then + echo "Key *key.pem not found." + exit 1; + fi + + cert=$(ls "$sign"/*cert.pem) + + if [ -z "$cert" ]; then + echo "Key *cert.pem not found." + exit 1; + fi + + ## Sign rpm system key + "$PSDK_DIR"/sdk-chroot rpmsign-external sign \ + --key "$key" \ + --cert "$cert" \ + build/aurora/arm/release/RPMS/*.rpm +fi + +if [ -n "$device" ]; then + + IFS=':' read -ra ADDR <<< "$device" + + D_IP="${ADDR[0]}" + D_PASS="${ADDR[1]}" + + # shellcheck disable=SC2012 + rpm=$(ls "$PWD"/build/aurora/arm/release/RPMS/*.rpm | sort -r | head -n 1) + + # upload rpm + scp "$rpm" defaultuser@"$D_IP:/home/defaultuser/Downloads" + + # install rpm + ssh -t defaultuser@"$D_IP" "echo $D_PASS | devel-su pkcon -y install-local /home/defaultuser/Downloads/$package*.rpm" + + # run application + ssh -t defaultuser@"$D_IP" "/usr/bin/$package" +fi