Package Exports
- tauri-plugin-app-control-api
Readme
Tauri Plugin: App Control
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.
Features (Primarily Android)
- Minimize App: Sends the Android app to the background (equivalent to pressing the Home button).
- Close App: Closes the current Android Activity.
- Exit App: Completely exits the Android application with options to:
- Remove from recents screen (Android Lollipop+).
- Forcefully kill the app process (use with caution).
- Check App State: Determines if the Android app is in the foreground, if the activity is finishing or destroyed, and provides the package name.
- Lifecycle Events (Android):
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 theexitApp
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.
Prerequisites
- Your Tauri project must be set up for Android development. Follow the official Tauri Android guide.
- This plugin is designed for Tauri 2.x.
Setup
There are two main parts to installing this plugin: the Rust (Core) part and the JavaScript (API Bindings) part.
1. Rust Crate Installation
Add the plugin to your Tauri app's src-tauri/Cargo.toml
.
A. Using cargo add
(Recommended for local development):
If you have the plugin locally:
cargo add tauri-plugin-app-control --path /path/to/your/tauri-plugin-app-control
(Replace /path/to/your/tauri-plugin-app-control
with the actual local path to this plugin's directory.)
If published to crates.io (once it is):\
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 = { path = "/path/to/your/tauri-plugin-app-control" }
# Or if published to crates.io (replace with actual version):
# tauri-plugin-app-control = "0.1.0"
2. Register the Plugin (Rust)
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");
}
3. JavaScript/TypeScript API Installation
The JavaScript bindings provide a typed API to interact with the plugin from your frontend code.
A. Install the NPM package:
The NPM package for this plugin is tauri-plugin-app-control-api
.
If you are developing the plugin locally and want to test it in another project, you should first link it. Navigate to the root of this plugin's directory (tauri-plugin-app-control
) and run:
# Using bun
bun link
# Using npm
npm link
# Using yarn v1 (classic)
yarn link
This makes the package tauri-plugin-app-control-api
available globally for linking.
Then, in your Tauri application's root directory (where your frontend package.json
is), link the package:
# 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
If this plugin were published to NPM, you would install it directly in your Tauri application:
# 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
4. Permissions (Tauri v2+)
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-app
allow-close-app
allow-exit-app
allow-is-app-in-foreground
If 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.
{
"$schema": "../gen/schemas/desktop-schema.json", // Or mobile-schema.json for mobile-focused apps
"identifier": "default",
"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 minimize_app
, close_app
, exit_app
, and is_app_in_foreground
commands when invoked from JavaScript, as these are included in the plugin's default
set (which internally references allow-minimize_app
, allow-close_app
, etc.).
Usage (JavaScript/TypeScript API)
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();
API Details
Commands (via JS API)
async minimizeApp(): Promise<MinimizeResult>
- Minimizes the Android application.
MinimizeResult
:{ success: boolean; message?: string; }
async closeApp(): Promise<CloseResult>
- Closes the current Android activity.
CloseResult
:{ success: boolean; message?: string; }
async exitApp(options?: ExitOptions): Promise<ExitResult>
- Exits the Android application completely.
ExitOptions
(Android only, all optional, defaults areremoveFromRecents: 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>
- Checks the current state of the Android application.
AppState
:inForeground: boolean
isFinishing: boolean
isDestroyed: boolean
(Android API 17+)packageName: string
Events (Android - via JS API)
Each 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; }
(extendsMinimizeResult
)
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; }
Rust API (for use within 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.
Android Specifics
- Utilizes native Android
Activity
lifecycle methods andActivityManager
. minimizeApp()
usesactivity.moveTaskToBack(true)
.closeApp()
callsactivity.finish()
.exitApp()
usesactivity.finishAndRemoveTask()
andandroid.os.Process.killProcess()
based on options.
Desktop Behavior
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.
Building the Plugin (Development)
- Navigate to the root directory of this plugin:
cd tauri-plugin-app-control
- Rust & Android Native Code:(The
cargo build # For host cargo build --target aarch64-linux-android # For Android (or other targets)
build.rs
script handles linking the Android Kotlin project during the Rust build process for mobile targets.) - JavaScript/TypeScript Bindings:
(Compiles
guest-js/*.ts
todist/
using Rollup)bun install # Or npm install, yarn install bun run build # Or npm run build, yarn build
Contributing
Contributions that align with the Android-centric focus of this plugin are welcome. Please open an issue or submit a pull request.
License
This plugin is licensed under either of
- Apache License, Version 2.0, (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.