new·Earn with mozg — 20% of every monthSend somebody here and take a fifth of every plan payment they make, for as long as they keep paying — not a bounty on the first invoice. Your handle is the link, the window is thirty days, and the commission lands on your balance the second they pay. Free to join: if you have signed in, you already have the link. mozg.sh/earnall news →
mozg.beta
Sign in

Tauri · all subjects

plugin development

38 notes, read out of this brain and free to use. Each one was extracted from a source and is re-checked against its exam.

Mobile plugins can execute native code in Kotlin, Java, and Swift

Plugins can execute native mobile code written in Kotlin (or Java) and Swift. The default plugin template includes an Android Library Project using Kotlin and a Swift Package with a sample mobile command showing how to trigger execution from Rust code.

Default plugin template splits implementation into desktop.rs and mobile.rs modules

The default plugin template divides plugin implementation into two separate modules: desktop.rs for Rust-based desktop functionality and mobile.rs for sending messages to native mobile code. Common logic shared between implementations should be defined in lib.rs.

Android plugin class requirements

An Android Tauri plugin is defined as a Kotlin class that extends app.tauri.plugin.Plugin and is annotated with @app.tauri.annotation.TauriPlugin. Each method annotated with @app.tauri.annotation.Command can be called from Rust or JavaScript. Tauri uses Kotlin by default but Java can be used by converting the file through Android Studio's conversion option.

iOS plugin class requirements

An iOS Tauri plugin is defined as a Swift class that extends the Plugin class from the Tauri package. Each function with the @objc attribute and (_invoke: Invoke) parameter, such as @objc private func download(_invoke: Invoke), can be called from Rust or JavaScript. Plugins are defined as Swift Packages allowing dependency management through Swift Package Manager.

Android plugin configuration with @InvokeArg

Android plugins receive plugin configuration through a getter command. Configuration classes must be annotated with @InvokeArg. The plugin's load(webView: WebView) lifecycle method retrieves configuration using getConfig(Config::class.java).let { this.property = it.property }.

iOS plugin configuration using parseConfig

iOS plugins retrieve configuration in the load(webview: WKWebView) lifecycle method using parseConfig(Config.self) within a do-catch block. Configuration structs must conform to Decodable.

Mobile plugin lifecycle events: load

The load event occurs when a plugin is loaded into the webview. Its purpose is to execute plugin initialization code. This is implemented as override fun load(webView: WebView) on Android and @objc public override func load(webview: WKWebView) on iOS.

Mobile plugin lifecycle event: onNewIntent (Android only)

The onNewIntent event occurs when an activity is resumed on Android only. Its purpose is to handle application resumption such as when notifications are clicked or deep links are accessed. It corresponds to Activity#onNewIntent(android.content.Intent). Implemented as override fun onNewIntent(intent: Intent).

Android mobile command with JSObject return

Android mobile commands are annotated with @Command and receive an Invoke parameter. Return data using invoke.resolve(jsObject) where JSObject contains the result data via ret.put(key, value) method calls.

Android suspend function in mobile commands using CoroutineScope

To use Kotlin suspend functions in Android mobile commands, create a custom CoroutineScope with val scope = CoroutineScope(Dispatchers.Default + SupervisorJob()) (or Dispatchers.IO for data fetching). Launch the coroutine with scope.launch { } and call the suspend function from within.

iOS mobile command with Invoke

iOS mobile commands are methods with @objc attribute and (_invoke: Invoke) parameter. Return data using invoke.resolve() with a dictionary like ["path": "/path/to/photo.jpg"].

Call mobile plugin commands from Rust using PluginHandle

Call mobile plugin commands from Rust using self.0.run_mobile_plugin(commandName, payload) where the command name is a String and payload is a serialized struct. The method returns Result<T> where T is the deserialized response type.

Android command arguments with @InvokeArg

Android command arguments are defined as classes annotated with @InvokeArg. Parse them using invoke.parseArgs(ClassName::class.java). Optional arguments are defined as var <name>: Type? = null. Arguments with defaults are var <name>: Type = <default-value>. Required arguments are lateinit var <name>: Type. Nested objects must also be annotated with @InvokeArg.

iOS command arguments with Decodable

iOS command arguments are defined as classes inheriting from Decodable. Parse them using try invoke.parseArgs(ClassName.self). Optional arguments are defined as var <name>: Type?. Default values are not supported; use nullable types instead and set defaults in the command function. Required arguments are let <name>: Type. Nested objects must also inherit Decodable.

Android plugin permissions with @TauriPlugin annotation

Define required Android plugin permissions in the @TauriPlugin annotation using a permissions array: @TauriPlugin(permissions = [Permission(strings = [Manifest.permission.POST_NOTIFICATIONS], alias = "postNotification")]). Each permission has a strings array of manifest permissions and an alias for internal identification.

iOS plugin permission handling with checkPermissions and requestPermissions

iOS plugins override checkPermissions and requestPermissions methods. checkPermissions returns a map of permission aliases to their state (e.g., "prompt", "granted"). requestPermissions handles the actual permission request and calls invoke.resolve with the updated permission states.

Tauri auto-implements checkPermissions and requestPermissions commands

Tauri automatically implements checkPermissions and requestPermissions commands for plugins. These two commands can be invoked directly from JavaScript or Rust using plugin:pluginName|checkPermissions and plugin:pluginName|requestPermissions command names.

Invoke plugin permission check from JavaScript

Use invoke<Permissions>('plugin:<plugin-name>|checkPermissions') to check plugin permission states from JavaScript. The response is an object mapping permission aliases to PermissionState values. Check for 'prompt-with-rationale' state to display rationale to the user.

Request plugin permissions from JavaScript

Use invoke<Permissions>('plugin:<plugin-name>|requestPermissions', { permissions: ['permissionAlias'] }) to request permissions from JavaScript. Pass an array of permission aliases. Returns an object with updated permission states.

Request plugin permissions from Rust using run_mobile_plugin

Request permissions from Rust using self.0.run_mobile_plugin::<PermissionResponse>("requestPermissions", requestPayload) where requestPayload is a serialized struct with boolean fields for each permission to request. Returns the response mapped to a PermissionResponse struct with PermissionState fields.

Android plugin events with trigger function

Android plugins emit events using trigger(eventName: String, eventData: JSObject). Call trigger within lifecycle methods like load or onNewIntent, or within command methods. Pass a JSObject populated with event.put(key, value) calls.

iOS plugin events with trigger function

iOS plugins emit events using trigger(eventName: String, data: [String: Any]). Call trigger within lifecycle methods like load or command methods. Pass a dictionary with event data.

Listen to plugin events from JavaScript using addPluginListener

Use addPluginListener(pluginName: String, eventName: String, handler: Function) from @tauri-apps/api/core to listen for plugin events in JavaScript. Returns a PluginListener that can be used to unlisten.

Mobile plugin development prerequisites

Mobile plugin development builds on concepts explained in the general Plugin Development section. Understanding that section is necessary before developing mobile plugins.

Plugin structure and composition

A Tauri plugin consists of a Cargo crate and an optional NPM package that provides API bindings for commands and events. Plugin projects can also include Android library projects and iOS Swift packages for mobile support.

Plugin naming convention

Tauri plugins use a prefix followed by the plugin name. The default prefix is 'tauri-plugin-'. When creating a new plugin with name 'myname', the generated crate name is 'tauri-plugin-myname' and the JavaScript NPM package name is 'tauri-plugin-myname-api'. For Tauri's own packages, the NPM naming convention is '@scope-name/plugin-myname'.

Plugin project initialization command

To bootstrap a new plugin project, run 'npx @tauri-apps/cli plugin new [name]'. Use the '--no-api' flag if an NPM package is not needed. Use '--android' or '--ios' flags to initialize plugin support for those platforms.

Plugin project directory structure

A generated plugin project contains: src/ with commands.rs, desktop.rs, error.rs, lib.rs, mobile.rs, and models.rs; permissions/ for command access rights files; android/ and ios/ for platform-specific code; guest-js/ for JavaScript API binding source code; dist-js/ for compiled assets from guest-js; Cargo.toml for Rust metadata; and package.json for NPM metadata.

Plugin lifecycle events

Plugins can hook into several lifecycle events: setup (when plugin is initialized), on_navigation (when webview starts navigation), on_webview_ready (when a new window is created), on_event (when event loop events are notified), and on_drop (when plugin is destroyed).

Setup lifecycle hook purpose

The setup lifecycle hook is called when the plugin is initialized. Its purpose is to register mobile plugins, manage state, and execute background tasks.

On navigation lifecycle hook behavior

The on_navigation hook is called when the webview starts navigation. Its purpose is to validate navigation and track URL changes. Returning false from this hook cancels the navigation.

On webview ready lifecycle hook purpose

The on_webview_ready hook is called when a new window is created. Its purpose is to run initialization scripts for all windows.

On event lifecycle hook purpose

The on_event hook is called for event loop event notifications. Its purpose is to handle core events such as window events, menu events, and application exit requests. It receives all RunEvent notifications from the event loop.

On drop lifecycle hook purpose

The on_drop hook is called when the plugin is destroyed. Its purpose is to execute code when the plugin is being dropped.

Exposing Rust APIs as plugin structures

Plugin APIs defined in desktop.rs and mobile.rs are exported to users as structures named after the plugin in PascalCase. When a plugin is set up, an instance of this structure is created and managed as state. Users can retrieve this structure using any Manager instance (AppHandle, App, Window, etc.) through an extension trait defined by the plugin.

Plugin command definition and access

Commands are defined in the commands.rs file and are standard Tauri application commands. They can access AppHandle and Window instances directly through dependency injection and check state just like application commands. To expose commands to the webview, they must be hooked into the invoke_handler() call in lib.rs.

Plugin command with dependency injection example

Commands can receive AppHandle, Window, and Channel instances through dependency injection. Example: '#[command] async fn upload<R: Runtime>(app: AppHandle<R>, window: Window<R>, on_progress: Channel, url: String) { ... }'

Plugin state management

Plugins can manage state the same way as Tauri applications. The state management approach is identical to standard Tauri application state management.

Give your agent this brain

plugin development — Tauri