Приложение Dart FFI и CLI

Как использовать Dart FFI и создать приложение с интерфейсом командной строки? Хм…

Все в одном ресурсе Flutter: https://flatteredwithflutter.com/dart-ffi-cli-dart2native/

Обсуждение на встрече:

Начинать…

Уровень: средний

Предварительные требования: установить пакет FFI и Args.

Мы кратко расскажем о

  1. Использование Dart FFI
  2. Получение истории входа пользователя (macOS)
  3. Создать приложение CLI

Примечание. Мы не будем подробно рассказывать о Dart FFI, так как ему посвящены хорошие статьи.

  1. Использование Dart FFI

FFI: (Интерфейс внешних функций) можно использовать для вызова API на основе языка C / C ++.

Статически связанная библиотека встроена в исполняемый образ приложения и загружается при запуске приложения.

Символы из статически связанной библиотеки можно загрузить с помощью DynamicLibrary.executable или DynamicLibrary.process.

Динамически подключаемая библиотека распространяется в отдельном файле или папке в приложении и загружается по запросу. Динамически подключаемую библиотеку можно загрузить в Dart через DynamicLibrary.open.

Как мы подойдем?

В этой статье мы будем использовать динамическую системную библиотеку.

Если вы хотите создать свою собственную динамическую библиотеку, прочтите это.

2. Получить историю входа пользователя (macOS).

Откройте терминал и введите эту команду

last login `username`
where username is before @ [username@Macbook-Pro]
  • Вы должны получить историю входа в систему. Наша цель - вызвать эту команду из Дарта.
  • Эта команда определена в системной динамической библиотеке, присутствующей в macOS.

В macOS системные библиотеки присутствуют в

/usr/lib/libSystem.dylib

Чтобы получить пути для разных ОС, посетите здесь.

Мы загрузим нашу динамическую библиотеку, указанную по пути выше, в Dart.

  • Импортируйте пакет dart ffi (присутствует внутри Flutter) как
import 'dart:ffi' as ffi

У этого есть класс DynamicLibrary. Мы вызываем метод open и загружаем нашу динамическую библиотеку (Dylibs.systemDyLib).

class Dylibs {
  static const String systemDyLib = '/usr/lib/libSystem.dylib';
  static const String systemSymbolName = 'system';
}

Каждая динамическая библиотека состоит из символов. Чтобы найти символы в библиотеке, обратитесь сюда.

Теперь получение истории входа пользователя попадает под символ Система.

  • Найдите символ в загруженной динамической библиотеке с помощью lookupFunction.

Мы указали функции SystemC и SystemDart, которые в основном

// C header typedef:
typedef SystemC = ffi.Void Function(ffi.Pointer<Utf8> command);
// Dart header typedef
typedef SystemDart = void Function(ffi.Pointer<Utf8> command);

Это объединяет функцию поиска и приводит к функции Dart.

  • Затем мы конвертируем команду (нашу последнюю команду входа в систему) во что-то, что C понимает, используя
/// Convert a [String] to a Utf8-encoded null-terminated C string.
/// Returns a malloc-allocated pointer to the result.
final cmd = Utf8.toUtf8(command);
  • Запустите команду, используя sysFunc(cmd)
  • Наконец, освободите память, поскольку C / C ++ не поддерживает сборку мусора.

3. Создайте приложение с интерфейсом командной строки

Мы создадим нашу собственную команду, которая будет содержать информацию и описание приложения CLI.

  • Создайте нашу команду

Мы используем CommandRunner и определяем нашу команду (last_login) с некоторым описанием как

  • Добавьте нашу последнюю команду входа в систему. Чтобы создавать свои собственные команды, вам необходимо расширить Command Class
// THIS ADDS OUR LAST LOGIN COMMAND
runner.addCommand(LastLoginCmd());

Примечание. LastLoginCmd - это наш собственный класс.

МЫ создаем класс абстрактной базовой команды и объявляем методы.

abstract class BaseCLICommand extends Command<dynamic> {
  String loadingMessage;
  void execCommand(String arg);
  @override
  Future<void> run() async {
    if (argResults.arguments.isEmpty) {
      throw Exception('😳😳 Please specify the argument');
    }
    final arg = argResults.arguments.first;
    final loadingMsg = '$loadingMessage $arg';
    stdout.write('$loadingMsg\n');
    execCommand(arg);
  }
}
  • argResults.arguments помогают нам получать данные, введенные пользователем.
  • stdout.write используется для вывода на консоль.
  • execCommand - это функция, которую определяет расширенный класс.

Наш LastLoginCmd расширяет указанный выше класс и реализует методы.

  • После того, как мы добавим команду, как указано выше
// THIS ADDS OUR LAST LOGIN COMMAND
runner.addCommand(LastLoginCmd());

Наконец, мы запускаем эту команду как

runner.run(args);

Последний шаг (преобразование в приложение CLI)

Мы используем силу

dart2native, который может компилировать программы Dart в автономные исполняемые файлы. С dart2native вы можете создавать инструменты для командной строки в macOS, Windows или Linux с помощью Dart.

  1. Перейдите в каталог, содержащий точку входа в дротик. Например

Мой каталог будет lib / ffi

2. Запустите команду

dart2native cmd_line.dart -o login_history

-o <path> или --output=<path> Создает вывод.

Это создает наше приложение CLI с именем login_history.

Окончательный результат

Интересные статьи, связанные с Flutter, здесь:







Исходный код для настольного приложения Flutter.