| Crates.io | tauri-plugin-app-control |
| lib.rs | tauri-plugin-app-control |
| version | 0.1.1 |
| created_at | 2025-05-29 11:02:10.383342+00 |
| updated_at | 2025-05-29 11:41:35.906356+00 |
| description | A Tauri plugin for Android application lifecycle control (minimize, close, exit, state). |
| homepage | https://github.com/your-username/tauri-plugin-app-control |
| repository | https://github.com/your-username/tauri-plugin-app-control |
| max_upload_size | |
| id | 1693681 |
| size | 169,061 |
A Tauri 2 plugin focused on providing comprehensive Android application lifecycle control. It allows you to programmatically minimize, close, and exit your Tauri application on Android, check its foreground/background state, and listen to native lifecycle events. Desktop functionality is included with stubbed implementations that return an UnsupportedPlatform error, clearly indicating that these features are mobile-centric.
plugin-loaded: Emitted when the native Android plugin part is loaded.app-resumed: Emitted when the app is brought back to the foreground or a new intent is received.app-minimized: Emitted after the app is successfully minimized.app-closing: Emitted just before the current activity closes.app-exiting: Emitted just before the app exits via the exitApp command.Desktop Behavior:
All functions will return an Error::UnsupportedPlatform when called on a desktop environment, as this plugin is specifically designed for Android control.
There are two main parts to installing this plugin: the Rust (Core) part and the JavaScript (API Bindings) part.
Add the plugin to your Tauri app's src-tauri/Cargo.toml.
A. Using cargo add (Recommended):
cargo add tauri-plugin-app-control
B. Manual Cargo.toml Edit:
Add the following to your src-tauri/Cargo.toml under [dependencies]:
tauri-plugin-app-control = "0.1.0" # Replace with the desired version from crates.io
For local development, if you have a modified version of the plugin locally, you can use a path dependency:
tauri-plugin-app-control = { path = "/path/to/your/local/tauri-plugin-app-control" }
Or cargo add tauri-plugin-app-control --path /path/to/your/local/tauri-plugin-app-control.
In your src-tauri/src/main.rs, register the plugin with Tauri's builder:
fn main() {
tauri::Builder::default()
.plugin(tauri_plugin_app_control::init()) // Add this line
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
The JavaScript bindings provide a typed API to interact with the plugin from your frontend code. The NPM package for this plugin is tauri-plugin-app-control-api.
A. Install the NPM package (Recommended): In your Tauri application's frontend project directory, install the package:
# Using bun
bun add tauri-plugin-app-control-api
# Using npm
npm install tauri-plugin-app-control-api
# Using pnpm
pnpm add tauri-plugin-app-control-api
# Using yarn
yarn add tauri-plugin-app-control-api
Ensure you install a version compatible with your Rust crate version (e.g., 0.1.0).
B. Local Development & Linking: If you are actively developing this plugin and want to test changes immediately in a consuming project:
tauri-plugin-app-control) and run:
# Using bun
bun link
# Using npm
npm link
# Using yarn v1 (classic)
yarn link
# Using bun
bun link tauri-plugin-app-control-api
# Using npm
npm link tauri-plugin-app-control-api
# Using yarn v1 (classic)
yarn link tauri-plugin-app-control-api
This setup ensures your consuming project uses your local plugin code. Remember to rebuild the plugin's JS bindings (bun run build in the plugin directory) after changes.
For Tauri v2 and later, you must explicitly grant permissions to your plugin's commands. The app-control plugin comes with a default permission set that allows all its commands.
In your app's src-tauri/capabilities/default.json (or your specific capability file, e.g., mobile.json), add the plugin's default permission set by referencing it as "app-control:default":
{
"$schema": "../gen/schemas/mobile-schema.json", // Or desktop-schema.json as appropriate
"identifier": "default", // Or your specific capability identifier
"description": "Default capabilities for the application.",
"windows": [
"main" // Ensure your main window identifier is listed
],
"permissions": [
"core:default", // Or other core permissions you use
"app-control:default" // Add this line
]
}
This grants permissions for the commands included in the plugin's default set. Internally, the default set defined by this plugin bundles the following autogenerated permissions:
allow-minimize-appallow-close-appallow-exit-appallow-is-app-in-foregroundIf you prefer to grant permissions individually instead of using the default set, you would reference them in your capabilities file like so:
"app-control:allow-minimize-app", "app-control:allow-close-app", etc.
Import the desired functions and types from the tauri-plugin-app-control-api package in your frontend code.
import {
minimizeApp,
closeApp,
exitApp,
isAppInForeground,
type ExitOptions, // TypeScript type
type MinimizeResult,
type CloseResult,
type ExitResult,
type AppState,
// Event listeners
onPluginLoaded,
onAppResumed,
onAppMinimized,
onAppClosing,
onAppExiting,
type PluginLoadedEvent,
type AppResumedEvent,
type AppMinimizedEvent,
type AppClosingEvent,
type AppExitingEvent,
type PluginListener // Type for the unlisten function
} from 'tauri-plugin-app-control-api';
// Example: Minimize the app (Android)
async function handleMinimize() {
try {
const result: MinimizeResult = await minimizeApp();
console.log('Minimize success:', result.success, 'Message:', result.message);
} catch (error) {
console.error('Failed to minimize:', error);
}
}
// Example: Exit the app with options (Android)
async function handleExit() {
const options: ExitOptions = {
removeFromRecents: true,
killProcess: false
};
try {
const result: ExitResult = await exitApp(options);
console.log('Exit success:', result.success, 'Message:', result.message);
} catch (error) {
console.error('Failed to exit:', error);
}
}
// Example: Check app state (Android)
async function checkState() {
try {
const state: AppState = await isAppInForeground();
console.log('App in foreground:', state.inForeground);
console.log('App is finishing:', state.isFinishing);
console.log('App is destroyed:', state.isDestroyed);
console.log('Package Name:', state.packageName);
} catch (error) {
console.error('Failed to check state:', error);
}
}
// Example: Listen to events (Android)
async function setupEventListeners() {
const unlistenLoaded: PluginListener = await onPluginLoaded((event: PluginLoadedEvent) => {
console.log('App Control Plugin Loaded:', event.message, 'Platform:', event.platform, 'API Level:', event.apiLevel);
});
const unlistenMinimized: PluginListener = await onAppMinimized((event: AppMinimizedEvent) => {
console.log('App Minimized:', event.success, event.message);
});
const unlistenResumed: PluginListener = await onAppResumed((event: AppResumedEvent) => {
console.log('App Resumed:', event.action, event.data, event.categories);
});
// Remember to clean up listeners when your component unmounts or they are no longer needed:
// unlistenLoaded.unlisten(); // or just call unlistenLoaded()
// unlistenMinimized.unlisten();
// unlistenResumed.unlisten();
}
setupEventListeners();
async minimizeApp(): Promise<MinimizeResult>
MinimizeResult: { success: boolean; message?: string; }async closeApp(): Promise<CloseResult>
CloseResult: { success: boolean; message?: string; }async exitApp(options?: ExitOptions): Promise<ExitResult>
ExitOptions (Android only, all optional, defaults are removeFromRecents: true, killProcess: false):
removeFromRecents?: boolean: Remove app from recents list (Lollipop+).killProcess?: boolean: Forcefully kill the app process.ExitResult: { success: boolean; message?: string; }async isAppInForeground(): Promise<AppState>
AppState:
inForeground: booleanisFinishing: booleanisDestroyed: boolean (Android API 17+)packageName: stringEach event listener function returns a Promise<PluginListener>, where PluginListener is an object with an unlisten: () => void method (or can be called directly as a function) to remove the event listener.
onPluginLoaded(handler: (event: PluginLoadedEvent) => void): Promise<PluginListener>
PluginLoadedEvent: { message: string; platform: string; apiLevel?: number; } (apiLevel is Android specific)onAppMinimized(handler: (event: AppMinimizedEvent) => void): Promise<PluginListener>
AppMinimizedEvent: { success: boolean; message?: string; } (extends MinimizeResult)onAppClosing(handler: (event: AppClosingEvent) => void): Promise<PluginListener>
AppClosingEvent: { message: string; timestamp: number; }onAppExiting(handler: (event: AppExitingEvent) => void): Promise<PluginListener>
AppExitingEvent: { removeFromRecents: boolean; killProcess: boolean; timestamp: number; }onAppResumed(handler: (event: AppResumedEvent) => void): Promise<PluginListener>
AppResumedEvent: { action: string; data?: string; categories?: string; }src-tauri)You can also use the plugin's functions directly from Rust code via the AppControlExt trait.
use tauri_plugin_app_control::{AppControlExt, ExitOptions, AppState, MinimizeResult};
// In a function where you have access to AppHandle, Window, etc.
fn example_rust_usage<R: tauri::Runtime>(app_handle: &tauri::AppHandle<R>) {
// Minimize
match app_handle.app_control().minimize_app() {
Ok(MinimizeResult { success, message }) => println!("Minimize success: {}, message: {}", success, message.unwrap_or_default()),
Err(e) => eprintln!("Minimize error: {:?}", e),
}
// Check foreground state
match app_handle.app_control().is_app_in_foreground() {
Ok(AppState { in_foreground, .. }) => println!("App in foreground from Rust: {}", in_foreground),
Err(e) => eprintln!("Error getting app state from Rust: {:?}", e),
}
// Exit app
let options = ExitOptions { remove_from_recents: true, kill_process: false };
if let Err(e) = app_handle.app_control().exit_app(options) {
eprintln!("Exit error from Rust: {:?}", e);
}
}
Note: When calling exit_app directly from Rust as shown above, the ExitOptions struct in Rust has non-optional fields (removeFromRecents: bool, killProcess: bool). This differs slightly from the JS API's optional fields due to how #[derive(Deserialize)] works with Option for command arguments versus direct struct instantiation.
Activity lifecycle methods and ActivityManager.minimizeApp() uses activity.moveTaskToBack(true).closeApp() calls activity.finish().exitApp() uses activity.finishAndRemoveTask() and android.os.Process.killProcess() based on options.As mentioned, on desktop platforms (Windows, macOS, Linux), all plugin functions (both from Rust and JS) will result in an Error::UnsupportedPlatform being returned. This is by design, as the core focus is Android control.
cd tauri-plugin-app-controlcargo build # For host
cargo build --target aarch64-linux-android # For Android (or other targets)
(The build.rs script handles linking the Android Kotlin project during the Rust build process for mobile targets.)guest-js/*.ts to dist/ using Rollup)
bun install # Or npm install, yarn install
bun run build # Or npm run build, yarn build
Contributions that align with the Android-centric focus of this plugin are welcome. Please open an issue or submit a pull request.
This plugin is licensed under either of
at your option.