Skip to content
Tauri 中文网

嵌入外部二进制文件

你可能需要嵌入外部二进制文件以向你的应用添加其他功能,或阻止用户安装其他依赖(例如 Node.js 或 Python)。我们将此二进制文件称为 sidecar

¥You may need to embed external binaries to add additional functionality to your application or prevent users from installing additional dependencies (e.g., Node.js or Python). We call this binary a sidecar.

二进制文件是用任何编程语言编写的可执行文件。常见用例是使用 pyinstaller 打包的 Python CLI 应用或 API 服务器。

¥Binaries are executables written in any programming language. Common use cases are Python CLI applications or API servers bundled using pyinstaller.

要打包你选择的二进制文件,你可以将 externalBin 属性添加到 tauri.conf.json 中的 tauri > bundle 对象。externalBin 配置需要一个字符串列表,该列表以绝对路径或相对路径为目标二进制文件。

¥To bundle the binaries of your choice, you can add the externalBin property to the tauri > bundle object in your tauri.conf.json. The externalBin configuration expects a list of strings targeting binaries either with absolute or relative paths.

以下是 Tauri 配置片段,用于说明 sidecar 配置:

¥Here is a Tauri configuration snippet to illustrate a sidecar configuration:

src-tauri/tauri.conf.json
{
"bundle": {
"externalBin": [
"/absolute/path/to/sidecar",
"../relative/path/to/binary",
"binaries/my-sidecar"
]
}
}

:::note 注意

相对路径是相对于 src-tauri 目录中的 tauri.conf.json 文件而言的。因此 binaries/my-sidecar 将代表 <PROJECT ROOT>/src-tauri/binaries/my-sidecar

¥The relative paths are relative to the tauri.conf.json file which is in the src-tauri directory. So binaries/my-sidecar would represent <PROJECT ROOT>/src-tauri/binaries/my-sidecar.

:::

要使外部二进制文件在每个受支持的体系结构上工作,指定路径上必须存在具有相同名称和 -$TARGET_TRIPLE 后缀的二进制文件。例如,"externalBin": ["binaries/my-sidecar"] 需要 Linux 上的 src-tauri/binaries/my-sidecar-x86_64-unknown-linux-gnu 可执行文件或 Mac OS 上带有 Apple Silicon 的 src-tauri/binaries/my-sidecar-aarch64-apple-darwin

¥To make the external binary work on each supported architecture, a binary with the same name and a -$TARGET_TRIPLE suffix must exist on the specified path. For instance, "externalBin": ["binaries/my-sidecar"] requires a src-tauri/binaries/my-sidecar-x86_64-unknown-linux-gnu executable on Linux or src-tauri/binaries/my-sidecar-aarch64-apple-darwin on Mac OS with Apple Silicon.

你可以通过查看以下命令报告的 host: 属性来找到当前平台的 -$TARGET_TRIPLE 后缀:

¥You can find your current platform’s -$TARGET_TRIPLE suffix by looking at the host: property reported by the following command:

Terminal window
rustc -Vv

如果 grepcut 命令可用(它们应该在大多数 Unix 系统上可用),你可以使用以下命令直接提取目标三元组:

¥If the grep and cut commands are available, as they should on most Unix systems, you can extract the target triple directly with the following command:

Terminal window
rustc -Vv | grep host | cut -f2 -d' '

在 Windows 上,你可以改用 PowerShell:

¥On Windows you can use PowerShell instead:

Terminal window
rustc -Vv | Select-String "host:" | ForEach-Object {$_.Line.split(" ")[1]}

以下是将目标三元组附加到二进制文件的 Node.js 脚本:

¥Here’s a Node.js script to append the target triple to a binary:

import { execSync } from 'child_process';
import fs from 'fs';
const extension = process.platform === 'win32' ? '.exe' : '';
const rustInfo = execSync('rustc -vV');
const targetTriple = /host: (\S+)/g.exec(rustInfo)[1];
if (!targetTriple) {
console.error('Failed to determine platform target triple');
}
fs.renameSync(
`src-tauri/binaries/sidecar${extension}`,
`src-tauri/binaries/sidecar-${targetTriple}${extension}`
);

请注意,如果你为与其运行的架构不同的架构进行编译,则此脚本将不起作用,因此仅将其用作你自己的构建脚本的起点。

¥Note that this script will not work if you compile for a different architecture than the one its running on, so only use it as a starting point for your own build scripts.

从 Rust 运行

¥Running it from Rust

:::note 注意

请首先按照 shell 插件指南 正确设置和初始化插件。如果插件未初始化和配置,示例将无法运行。

¥Please follow the shell plugin guide first to set up and initialize the plugin correctly. Without the plugin being initialized and configured the example won’t work.

:::

在 Rust 方面,导入 tauri_plugin_shell::ShellExt 特性并在 AppHandle 上调用 shell().sidecar() 函数:

¥On the Rust side, import the tauri_plugin_shell::ShellExt trait and call the shell().sidecar() function on the AppHandle:

use tauri_plugin_shell::ShellExt;
use tauri_plugin_shell::process::CommandEvent;
let sidecar_command = app.shell().sidecar("my-sidecar").unwrap();
let (mut rx, mut _child) = sidecar_command
.spawn()
.expect("Failed to spawn sidecar");
tauri::async_runtime::spawn(async move {
// read events such as stdout
while let Some(event) = rx.recv().await {
if let CommandEvent::Stdout(line_bytes) = event {
let line = String::from_utf8_lossy(&line_bytes);
window
.emit("message", Some(format!("'{}'", line)))
.expect("failed to emit event");
// write to stdin
child.write("message from Rust\n".as_bytes()).unwrap();
}
}
});

:::note 注意

sidecar() 函数只需要文件名,而不是 externalBin 数组中配置的整个路径。

¥The sidecar() function expects just the filename, NOT the whole path configured in the externalBin array.

给定以下配置:

¥Given the following configuration:

src-tauri/tauri.conf.json
{
"bundle": {
"externalBin": ["binaries/app", "my-sidecar", "../scripts/sidecar"]
}
}

执行 sidecar 的适当方法是调用 app.shell().sidecar(name),其中 name"app""my-sidecar""sidecar",而不是 "binaries/app"

¥The appropriate way to execute the sidecar is by calling app.shell().sidecar(name) where name is either "app", "my-sidecar" or "sidecar" instead of "binaries/app" for instance.

:::

你可以将此代码放在 Tauri 命令中以轻松传递 AppHandle,或者你可以将对 AppHandle 的引用存储在构建器脚本中以在应用的其他位置访问它。

¥You can place this code inside a Tauri command to easily pass the AppHandle or you can store a reference to the AppHandle in the builder script to access it elsewhere in your application.

从 JavaScript 运行

¥Running it from JavaScript

在运行 sidecar 时,Tauri 要求你授予 sidecar 在子进程上运行 executespawn 方法的权限。要授予此权限,请转到文件 <PROJECT ROOT>/src-tauri/capabilities/default.json 并将下面的部分添加到权限数组中。不要忘记根据前面提到的相对路径命名你的 sidecar。

¥When running the sidecar, Tauri requires you to give the sidecar permission to run the execute or spawn method on the child process. To grant this permission, go to the file <PROJECT ROOT>/src-tauri/capabilities/default.json and add the section below to the permissions array. Don’t forget to name your sidecar according to the relative path mentioned earlier.

src-tauri/capabilities/default.json
{
"permissions": [
"core:default",
{
"identifier": "shell:allow-execute",
"allow": [
{
"name": "binaries/app",
"sidecar": true
}
]
},
"shell:allow-open"
]
}

:::note 注意

使用 shell:allow-execute 标识符是因为 sidecar 的子进程将使用 command.execute() 方法启动。要使用 command.spawn() 运行它,你需要将标识符更改为 shell:allow-spawn 或向数组添加另一个条目,其结构与上面的相同,但标识符设置为 shell:allow-spawn

¥The shell:allow-execute identifier is used because the sidecar’s child process will be started using the command.execute() method. To run it with command.spawn(), you need to change the identifier to shell:allow-spawn or add another entry to the array with the same structure as the one above, but with the identifier set to shell:allow-spawn.

:::

在 JavaScript 代码中,从 @tauri-apps/plugin-shell 模块导入 Command 类并使用 sidecar 静态方法。

¥In the JavaScript code, import the Command class from the @tauri-apps/plugin-shell module and use the sidecar static method.

import { Command } from '@tauri-apps/plugin-shell';
const command = Command.sidecar('binaries/my-sidecar');
const output = await command.execute();

:::note 注意

提供给 Command.sidecar 的字符串必须与 externalBin 配置数组中定义的字符串之一匹配。

¥The string provided to Command.sidecar must match one of the strings defined in the externalBin configuration array.

:::

传递参数

¥Passing arguments

你可以像运行普通 命令 一样将参数传递给 Sidecar 命令。

¥You can pass arguments to Sidecar commands just like you would for running normal Command.

参数可以是静态的(例如 -oserve),也可以是动态的(例如 <file_path>localhost:<PORT>)。你按照调用它们的确切顺序定义参数。静态参数按原样定义,而动态参数可以使用正则表达式定义。

¥Arguments can be either static (e.g. -o or serve) or dynamic (e.g. <file_path> or localhost:<PORT>). You define the arguments in the exact order in which you’d call them. Static arguments are defined as-is, while dynamic arguments can be defined using a regular expression.

首先,在 src-tauri/capabilities/default.json 中定义需要传递给 sidecar 命令的参数:

¥First, define the arguments that need to be passed to the sidecar command in src-tauri/capabilities/default.json:

src-tauri/capabilities/default.json
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "default",
"description": "Capability for the main window",
"windows": ["main"],
"permissions": [
"core:default",
{
"identifier": "shell:allow-execute",
"allow": [
{
"args": [
"arg1",
"-a",
"--arg2",
{
"validator": "\\S+"
}
],
"name": "binaries/my-sidecar",
"sidecar": true
}
]
},
"shell:allow-open"
]
}

:::note 注意

如果你要从 Tauri v1 迁移,Tauri v2 CLI 中的 migrate 命令应该会为你处理这个问题。阅读 自动迁移 了解更多信息。

¥If you are migrating from Tauri v1, the migrate command in Tauri v2 CLI should take care of this for you. Read Automated Migration for more.

:::

然后,要调用 sidecar 命令,只需将所有参数作为数组传入即可。

¥Then, to call the sidecar command, simply pass in all the arguments as an array.

在 Rust 中:

¥In Rust:

use tauri_plugin_shell::ShellExt;
#[tauri::command]
async fn call_my_sidecar(app: tauri::AppHandle) {
let sidecar_command = app
.shell()
.sidecar("my-sidecar")
.unwrap()
.args(["arg1", "-a", "--arg2", "any-string-that-matches-the-validator"]);
let (mut _rx, mut _child) = sidecar_command.spawn().unwrap();
}

在 JavaScript 中:

¥In JavaScript:

import { Command } from '@tauri-apps/plugin-shell';
// notice that the args array matches EXACTLY what is specified in `capabilities/default.json`.
const command = Command.sidecar('binaries/my-sidecar', [
'arg1',
'-a',
'--arg2',
'any-string-that-matches-the-validator',
]);
const output = await command.execute();

Tauri 中文网 - 粤ICP备13048890号