@@ -18,6 +18,7 @@ use serde::{
1818} ;
1919use serde_json:: Value as JsonValue ;
2020use tauri_macros:: default_runtime;
21+ use tauri_runtime:: webview:: InitializationScript ;
2122use thiserror:: Error ;
2223use url:: Url ;
2324
@@ -50,15 +51,37 @@ pub trait Plugin<R: Runtime>: Send {
5051 /// Add the provided JavaScript to a list of scripts that should be run after the global object has been created,
5152 /// but before the HTML document has been parsed and before any other script included by the HTML document is run.
5253 ///
53- /// Since it runs on all top-level document and child frame page navigations,
54- /// it's recommended to check the `window.location` to guard your script from running on unexpected origins.
55- ///
5654 /// The script is wrapped into its own context with `(function () { /* your script here */ })();`,
5755 /// so global variables must be assigned to `window` instead of implicitly declared.
56+ ///
57+ /// This is executed only on the main frame.
58+ /// If you only want to run it in all frames, use [`Plugin::initialization_script_2`] to set that to false.
59+ ///
60+ /// ## Platform-specific
61+ ///
62+ /// - **Windows:** scripts are always added to subframes.
63+ /// - **Android:** When [addDocumentStartJavaScript] is not supported,
64+ /// we prepend initialization scripts to each HTML head (implementation only supported on custom protocol URLs).
65+ /// For remote URLs, we use [onPageStarted] which is not guaranteed to run before other scripts.
66+ ///
67+ /// [addDocumentStartJavaScript]: https://developer.android.com/reference/androidx/webkit/WebViewCompat#addDocumentStartJavaScript(android.webkit.WebView,java.lang.String,java.util.Set%3Cjava.lang.String%3E)
68+ /// [onPageStarted]: https://developer.android.com/reference/android/webkit/WebViewClient#onPageStarted(android.webkit.WebView,%20java.lang.String,%20android.graphics.Bitmap)
5869 fn initialization_script ( & self ) -> Option < String > {
5970 None
6071 }
6172
73+ // TODO: Change `initialization_script` to this in v3
74+ /// Same as [`Plugin::initialization_script`] but returns an [`InitializationScript`] instead
75+ /// We plan to replace [`Plugin::initialization_script`] with this signature in v3
76+ fn initialization_script_2 ( & self ) -> Option < InitializationScript > {
77+ self
78+ . initialization_script ( )
79+ . map ( |script| InitializationScript {
80+ script,
81+ for_main_frame_only : true ,
82+ } )
83+ }
84+
6285 /// Callback invoked when the window is created.
6386 #[ allow( unused_variables) ]
6487 fn window_created ( & mut self , window : Window < R > ) { }
@@ -242,7 +265,7 @@ pub struct Builder<R: Runtime, C: DeserializeOwned = ()> {
242265 name : & ' static str ,
243266 invoke_handler : Box < InvokeHandler < R > > ,
244267 setup : Option < Box < SetupHook < R , C > > > ,
245- js_init_script : Option < String > ,
268+ js_init_script : Option < InitializationScript > ,
246269 on_navigation : Box < OnNavigation < R > > ,
247270 on_page_load : Box < OnPageLoad < R > > ,
248271 on_window_ready : Box < OnWindowReady < R > > ,
@@ -305,14 +328,24 @@ impl<R: Runtime, C: DeserializeOwned> Builder<R, C> {
305328 /// Sets the provided JavaScript to be run after the global object has been created,
306329 /// but before the HTML document has been parsed and before any other script included by the HTML document is run.
307330 ///
308- /// Since it runs on all top-level document and child frame page navigations,
309- /// it's recommended to check the `window.location` to guard your script from running on unexpected origins.
310- ///
311331 /// The script is wrapped into its own context with `(function () { /* your script here */ })();`,
312332 /// so global variables must be assigned to `window` instead of implicitly declared.
313333 ///
314334 /// Note that calling this function multiple times overrides previous values.
315335 ///
336+ /// This is executed only on the main frame.
337+ /// If you only want to run it in all frames, use [`Self::js_init_script_on_all_frames`] instead.
338+ ///
339+ /// ## Platform-specific
340+ ///
341+ /// - **Windows:** scripts are always added to subframes.
342+ /// - **Android:** When [addDocumentStartJavaScript] is not supported,
343+ /// we prepend initialization scripts to each HTML head (implementation only supported on custom protocol URLs).
344+ /// For remote URLs, we use [onPageStarted] which is not guaranteed to run before other scripts.
345+ ///
346+ /// [addDocumentStartJavaScript]: https://developer.android.com/reference/androidx/webkit/WebViewCompat#addDocumentStartJavaScript(android.webkit.WebView,java.lang.String,java.util.Set%3Cjava.lang.String%3E)
347+ /// [onPageStarted]: https://developer.android.com/reference/android/webkit/WebViewClient#onPageStarted(android.webkit.WebView,%20java.lang.String,%20android.graphics.Bitmap)
348+ ///
316349 /// # Examples
317350 ///
318351 /// ```rust
@@ -328,13 +361,46 @@ impl<R: Runtime, C: DeserializeOwned> Builder<R, C> {
328361 ///
329362 /// fn init<R: Runtime>() -> TauriPlugin<R> {
330363 /// Builder::new("example")
331- /// .js_init_script(INIT_SCRIPT.to_string() )
364+ /// .js_init_script(INIT_SCRIPT)
332365 /// .build()
333366 /// }
334367 /// ```
335368 #[ must_use]
336- pub fn js_init_script ( mut self , js_init_script : String ) -> Self {
337- self . js_init_script = Some ( js_init_script) ;
369+ // TODO: Rename to `initialization_script` in v3
370+ pub fn js_init_script ( mut self , js_init_script : impl Into < String > ) -> Self {
371+ self . js_init_script = Some ( InitializationScript {
372+ script : js_init_script. into ( ) ,
373+ for_main_frame_only : true ,
374+ } ) ;
375+ self
376+ }
377+
378+ /// Sets the provided JavaScript to be run after the global object has been created,
379+ /// but before the HTML document has been parsed and before any other script included by the HTML document is run.
380+ ///
381+ /// Since it runs on all top-level document and child frame page navigations,
382+ /// it's recommended to check the `window.location` to guard your script from running on unexpected origins.
383+ ///
384+ /// Note that calling this function multiple times overrides previous values.
385+ ///
386+ /// This is executed on all frames, main frame and also sub frames.
387+ /// If you only want to run it in the main frame, use [`Self::js_init_script`] instead.
388+ ///
389+ /// ## Platform-specific
390+ ///
391+ /// - **Windows:** scripts are always added to subframes.
392+ /// - **Android:** When [addDocumentStartJavaScript] is not supported,
393+ /// we prepend initialization scripts to each HTML head (implementation only supported on custom protocol URLs).
394+ /// For remote URLs, we use [onPageStarted] which is not guaranteed to run before other scripts.
395+ ///
396+ /// [addDocumentStartJavaScript]: https://developer.android.com/reference/androidx/webkit/WebViewCompat#addDocumentStartJavaScript(android.webkit.WebView,java.lang.String,java.util.Set%3Cjava.lang.String%3E)
397+ /// [onPageStarted]: https://developer.android.com/reference/android/webkit/WebViewClient#onPageStarted(android.webkit.WebView,%20java.lang.String,%20android.graphics.Bitmap)
398+ #[ must_use]
399+ pub fn js_init_script_on_all_frames ( mut self , js_init_script : impl Into < String > ) -> Self {
400+ self . js_init_script = Some ( InitializationScript {
401+ script : js_init_script. into ( ) ,
402+ for_main_frame_only : false ,
403+ } ) ;
338404 self
339405 }
340406
@@ -695,7 +761,7 @@ pub struct TauriPlugin<R: Runtime, C: DeserializeOwned = ()> {
695761 app : Option < AppHandle < R > > ,
696762 invoke_handler : Box < InvokeHandler < R > > ,
697763 setup : Option < Box < SetupHook < R , C > > > ,
698- js_init_script : Option < String > ,
764+ js_init_script : Option < InitializationScript > ,
699765 on_navigation : Box < OnNavigation < R > > ,
700766 on_page_load : Box < OnPageLoad < R > > ,
701767 on_window_ready : Box < OnWindowReady < R > > ,
@@ -751,6 +817,13 @@ impl<R: Runtime, C: DeserializeOwned> Plugin<R> for TauriPlugin<R, C> {
751817 }
752818
753819 fn initialization_script ( & self ) -> Option < String > {
820+ self
821+ . js_init_script
822+ . clone ( )
823+ . map ( |initialization_script| initialization_script. script )
824+ }
825+
826+ fn initialization_script_2 ( & self ) -> Option < InitializationScript > {
754827 self . js_init_script . clone ( )
755828 }
756829
@@ -842,12 +915,20 @@ impl<R: Runtime> PluginStore<R> {
842915 }
843916
844917 /// Generates an initialization script from all plugins in the store.
845- pub ( crate ) fn initialization_script ( & self ) -> Vec < String > {
918+ pub ( crate ) fn initialization_script ( & self ) -> Vec < InitializationScript > {
846919 self
847920 . store
848921 . iter ( )
849- . filter_map ( |p| p. initialization_script ( ) )
850- . map ( |script| format ! ( "(function () {{ {script} }})();" ) )
922+ . filter_map ( |p| p. initialization_script_2 ( ) )
923+ . map (
924+ |InitializationScript {
925+ script,
926+ for_main_frame_only,
927+ } | InitializationScript {
928+ script : format ! ( "(function () {{ {script} }})();" ) ,
929+ for_main_frame_only,
930+ } ,
931+ )
851932 . collect ( )
852933 }
853934
0 commit comments