diff --git a/.changes/plugin-builder.md b/.changes/plugin-builder.md new file mode 100644 index 000000000..5751204cd --- /dev/null +++ b/.changes/plugin-builder.md @@ -0,0 +1,5 @@ +--- +"tauri": minor +--- + +Add a `plugin::Builder` struct to make plugin creation more convenient. diff --git a/core/tauri/src/plugin.rs b/core/tauri/src/plugin.rs index 2648d2345..b4de66d52 100644 --- a/core/tauri/src/plugin.rs +++ b/core/tauri/src/plugin.rs @@ -5,8 +5,8 @@ //! The Tauri plugin extension to expand Tauri functionality. use crate::{ - runtime::Runtime, utils::config::PluginConfig, AppHandle, Invoke, PageLoadPayload, RunEvent, - Window, + runtime::Runtime, utils::config::PluginConfig, AppHandle, Invoke, InvokeHandler, OnPageLoad, + PageLoadPayload, RunEvent, Window, }; use serde_json::Value as JsonValue; use tauri_macros::default_runtime; @@ -53,6 +53,145 @@ pub trait Plugin: Send { fn extend_api(&mut self, invoke: Invoke) {} } +type SetupHook = dyn Fn(&AppHandle) -> Result<()> + Send + Sync; +type OnWebviewReady = dyn Fn(Window) + Send + Sync; +type OnEvent = dyn Fn(&AppHandle, &RunEvent) + Send + Sync; + +/// Builds a [`TauriPlugin`]. +pub struct Builder { + name: &'static str, + invoke_handler: Box>, + setup: Box>, + js_init_script: Option, + on_page_load: Box>, + on_webview_ready: Box>, + on_event: Box>, +} + +impl Builder { + /// Creates a new Plugin builder. + pub fn new(name: &'static str) -> Self { + Self { + name, + setup: Box::new(|_| Ok(())), + js_init_script: None, + invoke_handler: Box::new(|_| ()), + on_page_load: Box::new(|_, _| ()), + on_webview_ready: Box::new(|_| ()), + on_event: Box::new(|_, _| ()), + } + } + + /// Defines the JS message handler callback. + pub fn invoke_handler(mut self, invoke_handler: F) -> Self + where + F: Fn(Invoke) + Send + Sync + 'static, + { + self.invoke_handler = Box::new(invoke_handler); + self + } + + /// The JS script to evaluate on webview initialization. + /// The script is wrapped into its own context with `(function () { /* your script here */ })();`, + /// so global variables must be assigned to `window` instead of implicity declared. + /// + /// It's guaranteed that this script is executed before the page is loaded. + pub fn js_init_script(mut self, js_init_script: String) -> Self { + self.js_init_script = Some(js_init_script); + self + } + + /// Define a closure that can setup plugin specific state. + pub fn setup(mut self, setup: F) -> Self + where + F: Fn(&AppHandle) -> Result<()> + Send + Sync + 'static, + { + self.setup = Box::new(setup); + self + } + + /// Callback invoked when the webview performs a navigation to a page. + pub fn on_page_load(mut self, on_page_load: F) -> Self + where + F: Fn(Window, PageLoadPayload) + Send + Sync + 'static, + { + self.on_page_load = Box::new(on_page_load); + self + } + + /// Callback invoked when the webview is created. + pub fn on_webview_ready(mut self, on_webview_ready: F) -> Self + where + F: Fn(Window) + Send + Sync + 'static, + { + self.on_webview_ready = Box::new(on_webview_ready); + self + } + + /// Callback invoked when the event loop receives a new event. + pub fn on_event(mut self, on_event: F) -> Self + where + F: Fn(&AppHandle, &RunEvent) + Send + Sync + 'static, + { + self.on_event = Box::new(on_event); + self + } + + /// Builds the [TauriPlugin]. + pub fn build(self) -> TauriPlugin { + TauriPlugin { + name: self.name, + invoke_handler: self.invoke_handler, + setup: self.setup, + js_init_script: self.js_init_script, + on_page_load: self.on_page_load, + on_webview_ready: self.on_webview_ready, + on_event: self.on_event, + } + } +} + +/// Plugin struct that is returned by the [`PluginBuilder`]. Should only be constructed through the builder. +pub struct TauriPlugin { + name: &'static str, + invoke_handler: Box>, + setup: Box>, + js_init_script: Option, + on_page_load: Box>, + on_webview_ready: Box>, + on_event: Box>, +} + +impl Plugin for TauriPlugin { + fn name(&self) -> &'static str { + self.name + } + + fn initialize(&mut self, app: &AppHandle, _: JsonValue) -> Result<()> { + (self.setup)(app) + } + + fn initialization_script(&self) -> Option { + self.js_init_script.clone() + } + + fn created(&mut self, window: Window) { + (self.on_webview_ready)(window) + } + + fn on_page_load(&mut self, window: Window, payload: PageLoadPayload) { + (self.on_page_load)(window, payload) + } + + fn on_event(&mut self, app: &AppHandle, event: &RunEvent) { + (self.on_event)(app, event) + } + + fn extend_api(&mut self, invoke: Invoke) { + (self.invoke_handler)(invoke) + } +} + /// Plugin collection type. #[default_runtime(crate::Wry, wry)] pub(crate) struct PluginStore {