如何获取 Dart 包中包含的资产的文件路径?
How to get the file path to an asset included in a Dart package?
我正在写一个 Dart 包(不是 Flutter)。我已经包含了一些位图图像作为 public 资产,例如 lib/assets/empty.png
。当此包 运行 作为最终用户的命令行应用程序时,我如何获取用户系统上这些资产的文件路径?
用例:我的 Dart 包调用 FFMPEG,我需要告诉 FFMPEG 在使用我的包的系统上哪里可以找到这些资产文件。例如,对 FFMPEG 的调用可能如下所示:
ffmpeg -i "path/to/lib/assets/empty.png" ...
可以通过两种方式访问 Dart 包的资产:
- 运行 带有
dart
工具并访问依赖项资产的 Dart CLI 应用程序,或
- 运行 一个可执行的 CLI 应用程序
这两种情况的区别在于,当您 运行 使用 dart
工具的 CLI 应用程序时,您的所有依赖项都可以作为系统本地缓存中的结构化包使用.但是,当您 运行 一个可执行文件时,所有相关代码都被编译成一个二进制文件,这意味着您无法在运行时访问依赖项的包,您只能访问依赖项的 tree-shaken, 编译代码.
在 运行 dart
时访问资产
以下代码会将包资产 URI 解析为文件系统路径。
final packageUri = Uri.parse('package:your_package/your/asset/path/some_file.whatever');
final future = Isolate.resolvePackageUri(packageUri);
// waitFor is strongly discouraged in general, but it is accepted as the
// only reasonable way to load package assets outside of Flutter.
// ignore: deprecated_member_use
final absoluteUri = waitFor(future, timeout: const Duration(seconds: 5));
final file = File.fromUri(absoluteUri);
if (file.existsSync()) {
return file.path;
}
此解析代码改编自 Tim Sneath 的 winmd
包:https://github.com/timsneath/winmd/blob/main/lib/src/metadatastore.dart#L84-L106
在 运行 可执行文件
时访问资产
将客户端应用程序编译为可执行文件时,该客户端应用程序根本无法访问与依赖包一起存储的任何资产文件。但是,有一种解决方法可能对某些人有用(它对我有用)。您可以将资产的 Base64 编码版本存储在包内的 Dart 代码中。
首先,将您的每个资产编码成一个 Base64 字符串,并将这些字符串存储在您的 Dart 代码中的某个位置。
const myAsset = "iVBORw0KGgoAAA....kJggg==";
然后,在运行时,将字符串解码回字节,然后将这些字节写入本地文件系统上的新文件。这是我在我的案例中使用的方法:
/// Writes this asset to a new file on the host's file system.
///
/// The file is written to [destinationDirectory], or the current
/// working directory, if no destination is provided.
String inflateToLocalFile([Directory? destinationDirectory]) {
final directory = destinationDirectory ?? Directory.current;
final file = File(directory.path + Platform.pathSeparator + fileName);
file.createSync(recursive: true);
final decodedBytes = base64Decode(base64encoded);
file.writeAsBytesSync(decodedBytes);
return file.path;
}
此方法由 @passsy
建议
我正在写一个 Dart 包(不是 Flutter)。我已经包含了一些位图图像作为 public 资产,例如 lib/assets/empty.png
。当此包 运行 作为最终用户的命令行应用程序时,我如何获取用户系统上这些资产的文件路径?
用例:我的 Dart 包调用 FFMPEG,我需要告诉 FFMPEG 在使用我的包的系统上哪里可以找到这些资产文件。例如,对 FFMPEG 的调用可能如下所示:
ffmpeg -i "path/to/lib/assets/empty.png" ...
可以通过两种方式访问 Dart 包的资产:
- 运行 带有
dart
工具并访问依赖项资产的 Dart CLI 应用程序,或 - 运行 一个可执行的 CLI 应用程序
这两种情况的区别在于,当您 运行 使用 dart
工具的 CLI 应用程序时,您的所有依赖项都可以作为系统本地缓存中的结构化包使用.但是,当您 运行 一个可执行文件时,所有相关代码都被编译成一个二进制文件,这意味着您无法在运行时访问依赖项的包,您只能访问依赖项的 tree-shaken, 编译代码.
在 运行 dart
时访问资产
以下代码会将包资产 URI 解析为文件系统路径。
final packageUri = Uri.parse('package:your_package/your/asset/path/some_file.whatever');
final future = Isolate.resolvePackageUri(packageUri);
// waitFor is strongly discouraged in general, but it is accepted as the
// only reasonable way to load package assets outside of Flutter.
// ignore: deprecated_member_use
final absoluteUri = waitFor(future, timeout: const Duration(seconds: 5));
final file = File.fromUri(absoluteUri);
if (file.existsSync()) {
return file.path;
}
此解析代码改编自 Tim Sneath 的 winmd
包:https://github.com/timsneath/winmd/blob/main/lib/src/metadatastore.dart#L84-L106
在 运行 可执行文件
时访问资产将客户端应用程序编译为可执行文件时,该客户端应用程序根本无法访问与依赖包一起存储的任何资产文件。但是,有一种解决方法可能对某些人有用(它对我有用)。您可以将资产的 Base64 编码版本存储在包内的 Dart 代码中。
首先,将您的每个资产编码成一个 Base64 字符串,并将这些字符串存储在您的 Dart 代码中的某个位置。
const myAsset = "iVBORw0KGgoAAA....kJggg==";
然后,在运行时,将字符串解码回字节,然后将这些字节写入本地文件系统上的新文件。这是我在我的案例中使用的方法:
/// Writes this asset to a new file on the host's file system.
///
/// The file is written to [destinationDirectory], or the current
/// working directory, if no destination is provided.
String inflateToLocalFile([Directory? destinationDirectory]) {
final directory = destinationDirectory ?? Directory.current;
final file = File(directory.path + Platform.pathSeparator + fileName);
file.createSync(recursive: true);
final decodedBytes = base64Decode(base64encoded);
file.writeAsBytesSync(decodedBytes);
return file.path;
}
此方法由 @passsy
建议