Skip to content

Commit 38198c4

Browse files
authored
feat: add documentation for 2.11 features (#3786)
1 parent 64dcb3e commit 38198c4

3 files changed

Lines changed: 471 additions & 1 deletion

File tree

src/content/docs/learn/index.mdx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,16 @@ For security related topics, you can learn about the permissions system. You wil
3232
/>
3333
</CardGrid>
3434

35-
To learn how to write your own splash screen or use a node.js sidecar, check out:
35+
To learn how to write your own splash screen, use a node.js sidecar, or set up mobile features, check out:
3636

3737
<CardGrid>
3838
<LinkCard title="Splashcreen" href="/learn/splashscreen/" />
3939
<LinkCard title="Node.js as a Sidecar" href="/learn/sidecar-nodejs/" />
40+
<LinkCard title="Multi-Window on Mobile" href="/learn/mobile-multiwindow/" />
41+
<LinkCard
42+
title="File Associations on Mobile"
43+
href="/learn/mobile-file-associations/"
44+
/>
4045
</CardGrid>
4146

4247
## More Resources
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
---
2+
title: File Associations on Mobile
3+
sidebar:
4+
order: 3
5+
i18nReady: false
6+
---
7+
8+
Tauri supports file associations on Android and iOS, allowing your app to be registered as a handler for specific file types. When a user opens a file that matches your declared associations, the operating system launches your app and delivers the file URL.
9+
10+
On **Android**, file associations are implemented using [intent filters](https://developer.android.com/training/app-links/deep-linking) that the Tauri build system generates automatically from your configuration.
11+
12+
On **iOS**, file associations use [CFBundleDocumentTypes](https://developer.apple.com/documentation/bundleresources/information-property-list/cfbundledocumenttypes) and optionally [UTExportedTypeDeclarations](https://developer.apple.com/documentation/bundleresources/information-property-list/utexportedtypedeclarations) for custom file types.
13+
14+
## Configuration
15+
16+
File associations are declared in `tauri.conf.json` under `bundle.fileAssociations`. The Tauri CLI uses this configuration to generate the appropriate platform-specific metadata (Android intent filters in `AndroidManifest.xml`, iOS document types in `Info.plist`).
17+
18+
Each entry in the array represents a file type your app can handle:
19+
20+
```json title="src-tauri/tauri.conf.json"
21+
{
22+
"bundle": {
23+
"fileAssociations": [
24+
{
25+
"ext": ["png"],
26+
"mimeType": "image/png"
27+
},
28+
{
29+
"ext": ["jpg", "jpeg"],
30+
"mimeType": "image/jpeg"
31+
}
32+
]
33+
}
34+
}
35+
```
36+
37+
### Configuration Options
38+
39+
- `ext` — list of file extensions to associate (without leading dot).
40+
- `mimeType` — the MIME type for the file (e.g. `image/png`). Required on Android for intent filter matching. Tauri infers common MIME types from extensions when not specified.
41+
- `role` — the app's role with respect to the file type. Maps to `CFBundleTypeRole` on Apple platforms. Values: `Editor` (default), `Viewer`, `Shell`, `QLGenerator`, `None`.
42+
- `rank` — the ranking among apps that handle this file type. Maps to `LSHandlerRank` on Apple platforms. Values: `Default` (default), `Owner`, `Alternate`, `None`.
43+
- `name` — display name for the file type. Defaults to the first extension.
44+
- `exportedType` — defines a custom file type owned by your app. Required on Apple platforms when associating with non-standard file extensions.
45+
- `androidIntentActionFilters` — which Android intent actions to register. Values: `Send`, `SendMultiple`, `View`. All three are used by default.
46+
47+
### Custom File Types
48+
49+
For non-standard file extensions, you should define an `exportedType` so Apple platforms can identify the file type. The `identifier` should be a reverse-DNS string unique to your app, and `conformsTo` lists the parent types:
50+
51+
```json title="src-tauri/tauri.conf.json"
52+
{
53+
"bundle": {
54+
"fileAssociations": [
55+
{
56+
"ext": ["mydata"],
57+
"mimeType": "application/octet-stream",
58+
"exportedType": {
59+
"identifier": "com.example.myapp.mydata",
60+
"conformsTo": ["public.data"]
61+
}
62+
}
63+
]
64+
}
65+
}
66+
```
67+
68+
Common `conformsTo` values include `public.data`, `public.image`, `public.json`, and `public.plain-text`.
69+
70+
## Handling Opened Files
71+
72+
When a file is opened with your app, Tauri emits a `RunEvent::Opened` event containing the file URLs. This event is available on macOS, iOS, and Android.
73+
74+
You need to handle two cases:
75+
76+
1. **App is already running** — the event is delivered at runtime.
77+
2. **App is launched by the file open** — the event fires during startup, so you should store the URLs and make them available to your frontend.
78+
79+
### Rust
80+
81+
Store incoming URLs in managed state, expose them with a command the frontend can call on startup, and emit a Tauri event whenever `RunEvent::Opened` fires so the frontend can react while the app is already running:
82+
83+
```rust title="src-tauri/src/lib.rs"
84+
use std::sync::Mutex;
85+
use tauri::Manager;
86+
87+
struct OpenedUrls(Mutex<Vec<tauri::Url>>);
88+
89+
#[tauri::command]
90+
fn opened_urls(app: tauri::AppHandle) -> Vec<tauri::Url> {
91+
app.state::<OpenedUrls>().0.lock().unwrap().clone()
92+
}
93+
94+
#[cfg_attr(mobile, tauri::mobile_entry_point)]
95+
pub fn run() {
96+
tauri::Builder::default()
97+
.manage(OpenedUrls(Mutex::new(vec![])))
98+
.invoke_handler(tauri::generate_handler![opened_urls])
99+
.build(tauri::generate_context!())
100+
.expect("error while running tauri application")
101+
.run(|app, event| {
102+
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "android"))]
103+
if let tauri::RunEvent::Opened { urls } = event {
104+
use tauri::Emitter;
105+
app.state::<OpenedUrls>()
106+
.0
107+
.lock()
108+
.unwrap()
109+
.extend(urls.clone());
110+
app.emit("opened", urls).unwrap();
111+
}
112+
});
113+
}
114+
```
115+
116+
### JavaScript
117+
118+
The frontend below is wired to that Rust code in two places:
119+
120+
- **`invoke('opened_urls')`** calls the `opened_urls` command, so the webview can read URLs that were stored before the UI finished loading (cold start from a file open).
121+
- **`listen('opened', …)`** subscribes to the same event name passed to **`app.emit("opened", urls)`** in Rust, so file open events that are triggered while the app is already running are delivered immediately.
122+
123+
```javascript
124+
import { listen } from '@tauri-apps/api/event';
125+
import { invoke } from '@tauri-apps/api/core';
126+
127+
// Cold start: URLs may already be in Rust state before the frontend loads
128+
const initialUrls = await invoke('opened_urls');
129+
if (initialUrls.length > 0) {
130+
handleFiles(initialUrls);
131+
}
132+
133+
// Warm: Rust emits the "opened" event when RunEvent::Opened fires
134+
await listen('opened', (event) => {
135+
handleFiles(event.payload);
136+
});
137+
```

0 commit comments

Comments
 (0)