managing-tauri-app-resources

Managing Tauri App Resources

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "managing-tauri-app-resources" with this command: npx skills add dchuk/claude-code-tauri-skills/dchuk-claude-code-tauri-skills-managing-tauri-app-resources

Managing Tauri App Resources

App Icons

Icon Generation

Generate all platform-specific icons from a single source file:

cargo tauri icon # Default: ./app-icon.png cargo tauri icon ./custom.png -o ./icons # Custom source/output cargo tauri icon --ios-color "#000000" # iOS background color

Source requirements: Squared PNG or SVG with transparency.

Generated Formats

Format Platform

icon.icns

macOS

icon.ico

Windows

*.png

Linux, Android, iOS

Configuration

{ "bundle": { "icon": [ "icons/32x32.png", "icons/128x128.png", "icons/128x128@2x.png", "icons/icon.icns", "icons/icon.ico" ] } }

Platform Requirements

Windows (.ico): Layers for 16, 24, 32, 48, 64, 256 pixels.

Android: No transparency. Place in src-tauri/gen/android/app/src/main/res/mipmap-* folders. Each needs ic_launcher.png , ic_launcher_round.png , ic_launcher_foreground.png .

iOS: No transparency. Place in src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/ . Required sizes: 20, 29, 40, 60, 76, 83.5 pixels with 1x/2x/3x scales, plus 512x512@2x.

Embedding Static Resources

Configuration

Array syntax (preserves directory structure):

{ "bundle": { "resources": ["./file.txt", "folder/", "docs/**/*.md"] } }

Map syntax (custom destinations):

{ "bundle": { "resources": { "path/to/source.json": "resources/dest.json", "docs/**/*.md": "website-docs/" } } }

Path Patterns

Pattern Behavior

"dir/file.txt"

Single file

"dir/"

Directory recursive

"dir/*"

Files non-recursive

"dir/**/*"

All files recursive

Accessing Resources - Rust

use tauri::Manager; use tauri::path::BaseDirectory;

#[tauri::command] fn load_resource(handle: tauri::AppHandle) -> Result<String, String> { let path = handle .path() .resolve("lang/de.json", BaseDirectory::Resource) .map_err(|e| e.to_string())?; std::fs::read_to_string(&path).map_err(|e| e.to_string()) }

Accessing Resources - JavaScript

import { resolveResource } from '@tauri-apps/api/path'; import { readTextFile } from '@tauri-apps/plugin-fs';

const resourcePath = await resolveResource('lang/de.json'); const content = await readTextFile(resourcePath); const data = JSON.parse(content);

Permissions

{ "permissions": [ "fs:allow-read-text-file", "fs:allow-resource-read-recursive" ] }

Use $RESOURCE/**/* scope for recursive access.

State Management

Basic Setup

use tauri::{Builder, Manager};

struct AppData { welcome_message: &'static str, }

fn main() { Builder::default() .setup(|app| { app.manage(AppData { welcome_message: "Welcome!", }); Ok(()) }) .run(tauri::generate_context!()) .unwrap() }

Thread-Safe Mutable State

use std::sync::Mutex; use tauri::{Builder, Manager};

#[derive(Default)] struct AppState { counter: u32, }

fn main() { Builder::default() .setup(|app| { app.manage(Mutex::new(AppState::default())); Ok(()) }) .run(tauri::generate_context!()) .unwrap() }

Accessing State in Commands

use std::sync::Mutex; use tauri::State;

#[tauri::command] fn increase_counter(state: State<'_, Mutex<AppState>>) -> u32 { let mut state = state.lock().unwrap(); state.counter += 1; state.counter }

#[tauri::command] fn get_counter(state: State<'_, Mutex<AppState>>) -> u32 { state.lock().unwrap().counter }

Async Commands with Tokio Mutex

use tokio::sync::Mutex; use tauri::State;

#[tauri::command] async fn increase_counter_async( state: State<'_, Mutex<AppState>> ) -> Result<u32, ()> { let mut state = state.lock().await; state.counter += 1; Ok(state.counter) }

Accessing State Outside Commands

use std::sync::Mutex; use tauri::{Manager, Window, WindowEvent};

fn on_window_event(window: &Window, event: &WindowEvent) { let app_handle = window.app_handle(); let state = app_handle.state::<Mutex<AppState>>(); let mut state = state.lock().unwrap(); state.counter += 1; }

Type Alias Pattern

Prevent runtime panics from type mismatches:

use std::sync::Mutex;

struct AppStateInner { counter: u32, }

type AppState = Mutex<AppStateInner>;

#[tauri::command] fn get_counter(state: State<'_, AppState>) -> u32 { state.lock().unwrap().counter }

Multiple State Types

use std::sync::Mutex; use tauri::{Builder, Manager, State};

struct UserState { username: Option<String> } struct AppSettings { theme: String }

fn main() { Builder::default() .setup(|app| { app.manage(Mutex::new(UserState { username: None })); app.manage(Mutex::new(AppSettings { theme: "dark".into() })); Ok(()) }) .run(tauri::generate_context!()) .unwrap() }

#[tauri::command] fn login(user_state: State<'_, Mutex<UserState>>, username: String) { user_state.lock().unwrap().username = Some(username); }

#[tauri::command] fn set_theme(settings: State<'_, Mutex<AppSettings>>, theme: String) { settings.lock().unwrap().theme = theme; }

Key Points

  • Arc not required - Tauri handles reference counting internally

  • Use std::sync::Mutex for most cases; Tokio's mutex only for holding locks across await points

  • Type safety - Wrong state types cause runtime panics, not compile errors; use type aliases

Complete Example

tauri.conf.json:

{ "bundle": { "icon": [ "icons/32x32.png", "icons/128x128.png", "icons/icon.icns", "icons/icon.ico" ], "resources": { "assets/config.json": "config.json", "assets/translations/": "lang/" } } }

src-tauri/src/main.rs:

use std::sync::Mutex; use serde::{Deserialize, Serialize}; use tauri::{Builder, Manager, State}; use tauri::path::BaseDirectory;

#[derive(Default)] struct AppState { counter: u32, locale: String } type ManagedState = Mutex<AppState>;

#[derive(Serialize, Deserialize)] struct Config { app_name: String, version: String }

#[tauri::command] fn increment(state: State<'_, ManagedState>) -> u32 { let mut s = state.lock().unwrap(); s.counter += 1; s.counter }

#[tauri::command] fn load_config(handle: tauri::AppHandle) -> Result<Config, String> { let path = handle.path() .resolve("config.json", BaseDirectory::Resource) .map_err(|e| e.to_string())?; let content = std::fs::read_to_string(&path).map_err(|e| e.to_string())?; serde_json::from_str(&content).map_err(|e| e.to_string()) }

fn main() { Builder::default() .setup(|app| { app.manage(Mutex::new(AppState::default())); Ok(()) }) .invoke_handler(tauri::generate_handler![increment, load_config]) .run(tauri::generate_context!()) .unwrap() }

Frontend:

import { invoke } from '@tauri-apps/api/core'; import { resolveResource } from '@tauri-apps/api/path'; import { readTextFile } from '@tauri-apps/plugin-fs';

const newValue = await invoke('increment'); const config = await invoke('load_config'); const langPath = await resolveResource('lang/en.json'); const translations = JSON.parse(await readTextFile(langPath));

Quick Reference

Icon Commands

cargo tauri icon # Generate from ./app-icon.png cargo tauri icon ./icon.png -o out # Custom source/output

Resource Patterns

{ "resources": ["data.json"] } // Single file { "resources": ["assets/"] } // Directory recursive { "resources": { "src/x.json": "x.json" }} // Custom destination

State Patterns

app.manage(Config { ... }); // Immutable app.manage(Mutex::new(State { ... })); // Mutable fn cmd(state: State<'_, Mutex<T>>) // In command app_handle.state::<Mutex<T>>() // Via AppHandle

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

integrating-tauri-js-frontends

No summary provided by upstream source.

Repository SourceNeeds Review
-138
dchuk
Coding

configuring-tauri-permissions

No summary provided by upstream source.

Repository SourceNeeds Review
-116
dchuk
Coding

understanding-tauri-architecture

No summary provided by upstream source.

Repository SourceNeeds Review