原文地址:levelup.gitconnected.com/dart-ffi-an…
发布时间:2020年11月23日 - 5分钟阅读
Dart FFI和CLI应用程序
如何使用Dart FFI并创建一个CLI App?嗯...
一体化的Flutter资源:flatteredwithflutter.com/dart-ffi-cl…
Meetup Talk:
Dart FFI和CLI
开始...
水平。中级
我们将简单介绍一下
- 使用Dart FFI
- 获取用户的登录历史(macOS)
- 创建一个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创建命令行的工具。
- 导航到包含你的dart入口点的目录。例如
我的目录是lib/ffi
- 运行命令
dart2native cmd_line.dart -o login_history
-o <path>
或 --output=<path>
生成输出。
这将创建我们的CLI应用程序,命名为login_history。
最后产出
与Flutter相关的有趣文章在这里。
通过www.DeepL.com/Translator(免费版)翻译