瀏覽代碼

refactor(core): app hooks (#1332)

Lucas Fernandes Nogueira 4 年之前
父節點
當前提交
dd5a945b7e
共有 3 個文件被更改,包括 81 次插入21 次删除
  1. 65 10
      tauri/src/app.rs
  2. 8 6
      tauri/src/app/utils.rs
  3. 8 5
      tauri/src/plugin.rs

+ 65 - 10
tauri/src/app.rs

@@ -1,5 +1,5 @@
 use futures::future::BoxFuture;
-use serde::Serialize;
+use serde::{Deserialize, Serialize};
 use serde_json::Value as JsonValue;
 use tauri_api::{config::Config, private::AsTauriContext};
 
@@ -23,7 +23,9 @@ pub use webview_manager::{WebviewDispatcher, WebviewManager};
 type InvokeHandler<A> = dyn Fn(WebviewManager<A>, String, JsonValue) -> BoxFuture<'static, crate::Result<InvokeResponse>>
   + Send
   + Sync;
-type Setup<A> = dyn Fn(WebviewManager<A>) -> BoxFuture<'static, ()> + Send + Sync;
+type ManagerHook<A> = dyn Fn(WebviewManager<A>) -> BoxFuture<'static, ()> + Send + Sync;
+type PageLoadHook<A> =
+  dyn Fn(WebviewManager<A>, PageLoadPayload) -> BoxFuture<'static, ()> + Send + Sync;
 
 /// `App` runtime information.
 pub struct Context {
@@ -63,12 +65,27 @@ impl<T: Serialize> From<T> for InvokeResponse {
   }
 }
 
+/// The payload for the "page_load" hook.
+#[derive(Debug, Clone, Deserialize)]
+pub struct PageLoadPayload {
+  url: String,
+}
+
+impl PageLoadPayload {
+  /// The page URL.
+  pub fn url(&self) -> &str {
+    &self.url
+  }
+}
+
 /// The application runner.
 pub struct App<A: ApplicationExt> {
   /// The JS message handler.
   invoke_handler: Option<Box<InvokeHandler<A>>>,
-  /// The setup callback, invoked when the webview is ready.
-  setup: Option<Box<Setup<A>>>,
+  /// The page load hook, invoked when the webview performs a navigation.
+  on_page_load: Option<Box<PageLoadHook<A>>>,
+  /// The setup hook, invoked when the webviews have been created.
+  setup: Option<Box<ManagerHook<A>>>,
   /// The context the App was created with
   pub(crate) context: Context,
   pub(crate) dispatchers: Arc<Mutex<HashMap<String, WebviewDispatcher<A::Dispatcher>>>>,
@@ -118,10 +135,22 @@ impl<A: ApplicationExt + 'static> App<A> {
     }
   }
 
-  /// Runs the setup callback if defined.
-  pub(crate) async fn run_setup(&self, dispatcher: &WebviewManager<A>) {
+  /// Runs the setup hook if defined.
+  pub(crate) async fn run_setup(&self, dispatcher: WebviewManager<A>) {
     if let Some(ref setup) = self.setup {
-      let fut = setup(dispatcher.clone());
+      let fut = setup(dispatcher);
+      fut.await;
+    }
+  }
+
+  /// Runs the on page load hook if defined.
+  pub(crate) async fn run_on_page_load(
+    &self,
+    dispatcher: &WebviewManager<A>,
+    payload: PageLoadPayload,
+  ) {
+    if let Some(ref on_page_load) = self.on_page_load {
+      let fut = on_page_load(dispatcher.clone(), payload);
       fut.await;
     }
   }
@@ -197,8 +226,10 @@ where
 {
   /// The JS message handler.
   invoke_handler: Option<Box<InvokeHandler<A>>>,
-  /// The setup callback, invoked when the webview is ready.
-  setup: Option<Box<Setup<A>>>,
+  /// The setup hook.
+  setup: Option<Box<ManagerHook<A>>>,
+  /// Page load hook.
+  on_page_load: Option<Box<PageLoadHook<A>>>,
   config: PhantomData<C>,
   /// The webview dispatchers.
   dispatchers: Arc<Mutex<HashMap<String, WebviewDispatcher<A::Dispatcher>>>>,
@@ -212,6 +243,7 @@ impl<A: ApplicationExt + 'static, C: AsTauriContext> AppBuilder<C, A> {
     Self {
       invoke_handler: None,
       setup: None,
+      on_page_load: None,
       config: Default::default(),
       dispatchers: Default::default(),
       webviews: Default::default(),
@@ -232,7 +264,7 @@ impl<A: ApplicationExt + 'static, C: AsTauriContext> AppBuilder<C, A> {
     self
   }
 
-  /// Defines the setup callback.
+  /// Defines the setup hook.
   pub fn setup<
     T: futures::Future<Output = ()> + Send + Sync + 'static,
     F: Fn(WebviewManager<A>) -> T + Send + Sync + 'static,
@@ -246,6 +278,20 @@ impl<A: ApplicationExt + 'static, C: AsTauriContext> AppBuilder<C, A> {
     self
   }
 
+  /// Defines the page load hook.
+  pub fn on_page_load<
+    T: futures::Future<Output = ()> + Send + Sync + 'static,
+    F: Fn(WebviewManager<A>, PageLoadPayload) -> T + Send + Sync + 'static,
+  >(
+    mut self,
+    on_page_load: F,
+  ) -> Self {
+    self.on_page_load = Some(Box::new(move |webview_manager, payload| {
+      Box::pin(on_page_load(webview_manager, payload))
+    }));
+    self
+  }
+
   /// Adds a plugin to the runtime.
   pub fn plugin(
     self,
@@ -283,6 +329,7 @@ impl<A: ApplicationExt + 'static, C: AsTauriContext> AppBuilder<C, A> {
     Ok(App {
       invoke_handler: self.invoke_handler,
       setup: self.setup,
+      on_page_load: self.on_page_load,
       context,
       dispatchers: self.dispatchers,
       webviews: Some(self.webviews),
@@ -303,6 +350,7 @@ fn run<A: ApplicationExt + 'static>(mut application: App<A>) -> crate::Result<()
 
   let application = Arc::new(application);
   let mut webview_app = A::new()?;
+  let mut main_webview_manager = None;
 
   for webview in webviews {
     let webview_label = webview.label.to_string();
@@ -311,6 +359,9 @@ fn run<A: ApplicationExt + 'static>(mut application: App<A>) -> crate::Result<()
       application.dispatchers.clone(),
       webview_label.to_string(),
     );
+    if main_webview_manager.is_none() {
+      main_webview_manager = Some(webview_manager.clone());
+    }
     let (webview_builder, rpc_handler, custom_protocol) =
       crate::async_runtime::block_on(application.init_webview(webview))?;
 
@@ -322,6 +373,10 @@ fn run<A: ApplicationExt + 'static>(mut application: App<A>) -> crate::Result<()
     ));
   }
 
+  if let Some(main_webview_manager) = main_webview_manager {
+    crate::async_runtime::block_on(application.run_setup(main_webview_manager));
+  }
+
   webview_app.run();
 
   Ok(())

+ 8 - 6
tauri/src/app/utils.rs

@@ -12,7 +12,7 @@ use crate::{
 
 use super::{
   webview::{CustomProtocol, WebviewBuilderExtPrivate, WebviewRpcHandler},
-  App, Context, RpcRequest, Webview, WebviewManager,
+  App, Context, PageLoadPayload, RpcRequest, Webview, WebviewManager,
 };
 
 use serde::Deserialize;
@@ -85,10 +85,10 @@ pub(super) fn initialization_script(
       {tauri_initialization_script}
       {event_initialization_script}
       if (window.rpc) {{
-        window.__TAURI__.invoke("__initialized")
+        window.__TAURI__.invoke("__initialized", {{ url: window.location.href }})
       }} else {{
         window.addEventListener('DOMContentLoaded', function () {{
-          window.__TAURI__.invoke("__initialized")
+          window.__TAURI__.invoke("__initialized", {{ url: window.location.href }})
         }})
       }}
       {plugin_initialization_script}
@@ -154,7 +154,6 @@ pub(super) fn build_webview<A: ApplicationExt + 'static>(
   plugin_initialization_script: &str,
   context: &Context,
 ) -> crate::Result<BuiltWebview<A>> {
-  // TODO let debug = cfg!(debug_assertions);
   let webview_url = match &webview.url {
     WindowUrl::App => content_url.to_string(),
     WindowUrl::Custom(url) => url.to_string(),
@@ -324,8 +323,11 @@ async fn on_message<A: ApplicationExt + 'static>(
   message: Message,
 ) -> crate::Result<InvokeResponse> {
   if &command == "__initialized" {
-    application.run_setup(&webview_manager).await;
-    crate::plugin::ready(A::plugin_store(), &webview_manager).await;
+    let payload: PageLoadPayload = serde_json::from_value(message.inner)?;
+    application
+      .run_on_page_load(&webview_manager, payload.clone())
+      .await;
+    crate::plugin::on_page_load(A::plugin_store(), &webview_manager, payload).await;
     Ok(().into())
   } else {
     let response = if let Some(module) = &message.tauri_module {

+ 8 - 5
tauri/src/plugin.rs

@@ -1,4 +1,6 @@
-use crate::{api::config::PluginConfig, async_runtime::Mutex, ApplicationExt, WebviewManager};
+use crate::{
+  api::config::PluginConfig, async_runtime::Mutex, ApplicationExt, PageLoadPayload, WebviewManager,
+};
 
 use futures::future::join_all;
 use serde_json::Value as JsonValue;
@@ -30,9 +32,9 @@ pub trait Plugin<A: ApplicationExt + 'static>: Send + Sync {
   #[allow(unused_variables)]
   async fn created(&mut self, webview_manager: WebviewManager<A>) {}
 
-  /// Callback invoked when the webview is ready.
+  /// Callback invoked when the webview performs a navigation.
   #[allow(unused_variables)]
-  async fn ready(&mut self, webview_manager: WebviewManager<A>) {}
+  async fn on_page_load(&mut self, webview_manager: WebviewManager<A>, payload: PageLoadPayload) {}
 
   /// Add invoke_handler API extension commands.
   #[allow(unused_variables)]
@@ -109,14 +111,15 @@ pub(crate) async fn created<A: ApplicationExt + 'static>(
   join_all(futures).await;
 }
 
-pub(crate) async fn ready<A: ApplicationExt + 'static>(
+pub(crate) async fn on_page_load<A: ApplicationExt + 'static>(
   store: &PluginStore<A>,
   webview_manager: &crate::WebviewManager<A>,
+  payload: PageLoadPayload,
 ) {
   let mut plugins = store.lock().await;
   let mut futures = Vec::new();
   for plugin in plugins.iter_mut() {
-    futures.push(plugin.ready(webview_manager.clone()));
+    futures.push(plugin.on_page_load(webview_manager.clone(), payload.clone()));
   }
   join_all(futures).await;
 }