Этот репозиторий содержит Flutter плагины для платформы ОС Аврора.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

7.5 KiB

FFI Plugin package

Специализированный пакет Dart, содержащий API, написанный на Dart, с одной или несколькими реализациями для конкретной платформы, использующими Dart FFI.

Для демонстрации создания платформо-зависимого плагина для ОС Аврора типа "FFI Plugin package" был написан и опубликован проект "Demo Dart Packages" которые подробно описан в статье "Flutter на ОС Аврора".

Проект "Demo Dart Packages" содержит в себе пакет реализующий платформо-зависимый плагин для ОС Аврора типа "FFI Plugin package". Данный пакет использует API ОС Аврора - "Device Info API". Плагин использует QtDBus но не является типом плагина "Qt plugin package" так как не использует сигналы и слоты.

Создать пакет "FFI Plugin package" можно командой:

$ flutter-aurora create --template=plugin_ffi <package-name>

Рассмотрим плагин "ffi_plugin_device" из проекта Demo Dart Packages. ffi_plugin_device - платформо-зависимая реализация плагина "Flutter Device" для ОС Аврора типа "FFI Plugin package".

Структура пакета ffi_plugin_device

└── 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. Пакет, предоставляющий утилиты для работы с кодом интерфейса внешних функций, называется ffi. В pubspec.yaml плагина нужно добавить зависимости и активировать ffiPlugin для платформы ОС Аврора.

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

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.

Файл packages/aurora/ffi_plugin_device/src/ffi_plugin_device.h

#ifdef __cplusplus
extern "C" {
#endif

char *getDeviceName();

#ifdef __cplusplus
}
#endif

Файл packages/aurora/ffi_plugin_device/src/ffi_plugin_device.cpp

#include <QStandardPaths>
#include <QtDBus/QtDBus>

#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<QString> reply = iface.call("getDeviceModel");
            if (reply.isValid()) {
                deviceName = reply.value();
            }
        }
    }
    return deviceName.toUtf8().data();
}

Выполнить генерацию FFI-привязок можно следующей командой, выполнив её из корня плагина (например, packages/aurora/ffi_plugin_device):

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

import 'dart:ffi' as ffi;

/// Bindings for `src/ffi_plugin_device.h`.
class PluginDeviceBindings {
  /// Holds the symbol lookup function.
  final ffi.Pointer<T> Function<T extends ffi.NativeType>(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<T> Function<T extends ffi.NativeType>(String symbolName)
          lookup)
      : _lookup = lookup;

  ffi.Pointer<ffi.Char> getDeviceName() {
    return _getDeviceName();
  }

  late final _getDeviceNamePtr =
      _lookup<ffi.NativeFunction<ffi.Pointer<ffi.Char> Function()>>(
          'getDeviceName');
  late final _getDeviceName =
      _getDeviceNamePtr.asFunction<ffi.Pointer<ffi.Char> Function()>();
}

Теперь можно создать класс FFIPluginDevice, реализующий интерфейс device_platform_interface.

Файл packages/aurora/ffi_plugin_device/lib/ffi_plugin_device.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<String?> get deviceName async {
    // Получение deviceName
    final deviceName = _bindings.getDeviceName().cast<Utf8>().toDartString();
    // Возврат результата
    return deviceName == '' ? null : deviceName;
  }
}