[Dart翻译]Dart FFI和CLI应用程序

911 阅读4分钟

原文地址:levelup.gitconnected.com/dart-ffi-an…

原文作者:medium.com/@aseemwango…

发布时间:2020年11月23日 - 5分钟阅读

Dart FFI和CLI应用程序

如何使用Dart FFI并创建一个CLI App?嗯...

一体化的Flutter资源:flatteredwithflutter.com/dart-ffi-cl…

Meetup Talk:

www.youtube.com/watch?v=xMd…

www.youtube.com/watch?v=jKb…

Dart FFI和CLI

开始...

水平。中级

前提条件。安装FFIArgs软件包

我们将简单介绍一下

  1. 使用Dart FFI
  2. 获取用户的登录历史(macOS)
  3. 创建一个CLI应用程序

注:关于Dart FFI我们就不深入解释了,因为有专门的好文章。

Dart FFI和CLI应用程序


1. 使用Dart FFI

FFI。(Foreign Function Interface)可以用来调用基于C/C++语言的API。

Dart FFI和CLI应用程序

静态链接库被嵌入到应用程序的可执行图像中,并在应用程序启动时被加载。

可以使用 DynamicLibrary.executable 或 DynamicLibrary.process 加载静态链接库中的符号。

动态链接库分布在应用程序中的一个单独的文件或文件夹中,并按需加载。动态链接库可以通过DynamicLibrary.open加载到Dart中。

我们将如何接近?

在本文中,我们将利用动态系统库。

如果你想创建自己的动态库,请阅读这个


2. 获取用户的登录历史记录(macOS)

打开终端,输入以下命令

last login `username`
where username is before @ [username@Macbook-Pro]
  • 你应该得到你的登录历史。我们的目标是在Dart中调用这个命令。
  • 这个命令是在系统动态库中定义的,存在于macOS中。

在macOS中,系统库存在于

/usr/lib/libSystem.dylib

要获取不同操作系统的路径,请访问这里

我们将在Dart中加载我们的动态库,在上面指定的路径。

Dart FFI和CLI应用程序

  • 将dart ffi包(存在于Flutter内)导入为
import 'dart:ffi' as ffi

这有一个类DynamicLibrary。我们调用该方法打开并加载我们的动态库(Dylibs.systemDyLib)。

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

每个动态库都是由符号组成的。关于如何查找库中的符号,请参考这里

现在,获取用户登录历史属于系统符号。

Dart FFI和CLI应用程序

  • 使用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应用程序

我们将创建自己的命令,其中将有关于CLI应用程序的信息和描述。

Dart FFI和CLI应用程序

  • 创建我们的命令

我们使用CommandRunner,并定义我们的命令(last_login),并加上一些描述为

CLI中的CommandRunner

  • 添加我们最后的登录命令。为了创建您自己的命令,您需要扩展命令类
// 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扩展了上述类并实现了这些方法。

LastLoginCmd

  • 在我们添加了上面的命令后
// THIS ADDS OUR LAST LOGIN COMMAND
runner.addCommand(LastLoginCmd());

最后,我们以

runner.run(args);

最后一步(转换为CLI应用程序

我们利用dart2native,它能够将Dart程序编译成自带的可执行文件。有了dart2native,你可以在macOS、Windows或Linux上使用Dart创建命令行的工具。

  1. 导航到包含你的dart入口点的目录。例如

我的目录是lib/ffi

  1. 运行命令
dart2native cmd_line.dart -o login_history

-o <path>--output=<path>生成输出。

这将创建我们的CLI应用程序,命名为login_history。

最后产出

与Flutter相关的有趣文章在这里。

Flutter桌面应用的源码。


通过www.DeepL.com/Translator(免费版)翻译