Files
archived-tauri-docs/src/content/docs/develop/sidecar.mdx

214 lines
6.7 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: Embedding External Binaries
sidebar:
order: 1
badge:
text: WIP
variant: caution
---
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`.
Binaries are executables written in any programming language. Common use cases are Python CLI applications or API servers bundled using `pyinstaller`.
To bundle the binaries of your choice, you can add the `externalBin` property to the `tauri > bundle` object in your `tauri.conf.json`. `externalBin` expects a list of strings targeting binaries either with absolute or relative paths.
Here is a sample to illustrate the configuration. This is not a complete `tauri.conf.json` file:
```json title="src-tauri/tauri.conf.json"
{
"tauri": {
"bundle": {
"externalBin": [
"/absolute/path/to/sidecar",
"relative/path/to/binary",
"binaries/my-sidecar"
]
}
}
}
```
:::note
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`.
:::
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.
You can find your **current** platform's `-$TARGET_TRIPLE` suffix by looking at the `host:` property reported by the `rustc -Vv` command.
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:
```shell
rustc -Vv | grep host | cut -f2 -d' '
```
On Windows you can use PowerShell instead:
```powershell
rustc -Vv | Select-String "host:" | ForEach-Object {$_.Line.split(" ")[1]}
```
Here's a Node.js script to append the target triple to a binary:
```javascript
const execa = require('execa');
const fs = require('fs');
let extension = '';
if (process.platform === 'win32') {
extension = '.exe';
}
async function main() {
const rustInfo = (await execa('rustc', ['-vV'])).stdout;
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}`
);
}
main().catch((e) => {
throw e;
});
```
## Running it from Rust
On the Rust side, import the `tauri_plugin_shell::ShellExt` trait and call the `shell().sidecar()` function on the AppHandle:
```rust
use tauri_plugin_shell::ShellExt;
use tauri_plugin_shell::process::CommandEvent;
// `sidecar()` expects just the filename, NOT the whole path like in JavaScript
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) = event {
window
.emit("message", Some(format!("'{}'", line)))
.expect("failed to emit event");
// write to stdin
child.write("message from Rust\n".as_bytes()).unwrap();
}
}
});
```
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.
## Running it from JavaScript
In the JavaScript code, import the `Command` class from the `@tauri-apps/plugin-shell` module and use the `sidecar` static method.
```javascript
import { Command } from '@tauri-apps/plugin-shell';
// `binaries/my-sidecar` is the EXACT value specified on `tauri.conf.json > tauri > bundle > externalBin`
const sidecar_command = Command.sidecar('binaries/my-sidecar');
const output = await sidecar_command.execute();
```
## Passing arguments
You can pass arguments to Sidecar commands just like you would for running normal `Command`s.
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.
First, define the arguments that need to be passed to the sidecar command in `src-tauri/capabilities/main.json`:
```json title="src-tauri/capabilities/main.json" ins={14-31}
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "default",
"description": "Capability for the main window",
"windows": ["main"],
"permissions": [
"path:default",
"event:default",
"window:default",
"app:default",
"resources:default",
"menu:default",
"tray:default",
{
"identifier": "shell:allow-execute",
"allow": [
{
"args": [
"arg1",
"-a",
"--arg2",
{
"validator": "\\S+"
}
],
"cmd": "",
"name": "binaries/my-sidecar",
"sidecar": true
}
]
},
"shell:allow-open"
]
}
```
:::note
If you are migrating from Tauri v1, the `migrate` command in Tauri v2 CLI should take care of this for you. Read [Automated Migration](/start/migrate/from-tauri-1/#automated-migration) for more.
:::
Then, to call the sidecar command, simply pass in **all** the arguments as an array.
In Rust:
```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();
}
```
In JavaScript:
```javascript
import { Command } from '@tauri-apps/plugin-shell';
// `binaries/my-sidecar` is the EXACT value specified on `tauri.conf.json > tauri > bundle > externalBin`
// notice that the args array matches EXACTLY what is specified on `tauri.conf.json`.
const command = Command.sidecar('binaries/my-sidecar', [
'arg1',
'-a',
'--arg2',
'any-string-that-matches-the-validator',
]);
const output = await command.execute();
```
:::note
Example: For a set of arguments like: `-i /path/to/input.png -o /path/to/output.txt`, the arguments array would look like
```json
["-i", { "validator": "\\S+" }, "-o", { "validator": "\\S+" }]
```
Here, the first and third arguments are static (`-i` and `-o`), but the second and fourth are dynamic and match the regex pattern described (`\\S+` means anything except space).
:::