AppHandle: la llave de todo
El argumento más útil de los tres: da acceso a las ventanas, las rutas, el estado, los eventos y los plugins, y se puede clonar y llevar a otro hilo. Qué se hace con él y por qué es lo que una tarea de fondo necesita.
Qué da
Las rutas, que es el uso más frecuente
#[tauri::command]async fn guardar_nota(app: tauri::AppHandle, texto: String) -> Result<(), ErrorPayload> { let dir = app.path().app_data_dir()?; // distinto en cada plataforma std::fs::create_dir_all(&dir)?; // puede no existir la primera vez std::fs::write(dir.join("nota.txt"), texto)?; Ok(())}Dos detalles que ahorran un fallo cada uno:
- El directorio de datos puede no existir todavía. El sistema no lo crea por ti: la primera ejecución de una instalación nueva se encuentra con que no está. Crearlo antes de escribir es una línea y evita un error que solo aparece en máquinas limpias, que son justo las de tus usuarios.
- La ruta es distinta en cada plataforma, y de ahí que se pregunte en vez de escribirse. El nivel 39 tiene el mapa completo de qué directorio sirve para qué.
Clonarlo y llevarlo a otro hilo
Es lo que lo distingue de los otros dos argumentos inyectados:
#[tauri::command]async fn empezar_indexado(app: tauri::AppHandle) -> Result<(), ErrorPayload> { let app = app.clone(); // barato: es un manejador, no la app tauri::async_runtime::spawn(async move { for (hechos, total) in indexar_todo().await { // la tarea sigue viva mucho después de que el comando haya vuelto, // y sigue pudiendo hablar con la aplicación let _ = app.emit("indexado-progreso", (hechos, total)); } }); Ok(()) // el comando vuelve enseguida}Ese patrón —el comando arranca el trabajo y vuelve, y el progreso llega por eventos— es el que resuelve la familia de operaciones largas, y es el nivel 21 y el 23. Lo que aquí importa es la pieza que lo hace posible: clonar el manejador es barato y el clon sirve para lo mismo.
Y fuera de un comando
El manejador también se obtiene en el gancho de inicialización, que es donde se hace casi toda la configuración real:
.setup(|app| { // aquí `app` es &App, y da un manejador clonable let handle = app.handle().clone(); tauri::async_runtime::spawn(async move { comprobar_actualizaciones(&handle).await; }); Ok(())})Es la forma de arrancar el trabajo de fondo que el nivel 4.2 pedía sacar de setup: se lanza la tarea con su copia del manejador y setup vuelve enseguida.