@@ -18,6 +18,7 @@ use serde::{
18
18
} ;
19
19
use serde_json:: Value as JsonValue ;
20
20
use tauri_macros:: default_runtime;
21
+ use tauri_runtime:: webview:: InitializationScript ;
21
22
use thiserror:: Error ;
22
23
use url:: Url ;
23
24
@@ -50,15 +51,37 @@ pub trait Plugin<R: Runtime>: Send {
50
51
/// Add the provided JavaScript to a list of scripts that should be run after the global object has been created,
51
52
/// but before the HTML document has been parsed and before any other script included by the HTML document is run.
52
53
///
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
- ///
56
54
/// The script is wrapped into its own context with `(function () { /* your script here */ })();`,
57
55
/// 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)
58
69
fn initialization_script ( & self ) -> Option < String > {
59
70
None
60
71
}
61
72
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
+
62
85
/// Callback invoked when the window is created.
63
86
#[ allow( unused_variables) ]
64
87
fn window_created ( & mut self , window : Window < R > ) { }
@@ -242,7 +265,7 @@ pub struct Builder<R: Runtime, C: DeserializeOwned = ()> {
242
265
name : & ' static str ,
243
266
invoke_handler : Box < InvokeHandler < R > > ,
244
267
setup : Option < Box < SetupHook < R , C > > > ,
245
- js_init_script : Option < String > ,
268
+ js_init_script : Option < InitializationScript > ,
246
269
on_navigation : Box < OnNavigation < R > > ,
247
270
on_page_load : Box < OnPageLoad < R > > ,
248
271
on_window_ready : Box < OnWindowReady < R > > ,
@@ -305,14 +328,24 @@ impl<R: Runtime, C: DeserializeOwned> Builder<R, C> {
305
328
/// Sets the provided JavaScript to be run after the global object has been created,
306
329
/// but before the HTML document has been parsed and before any other script included by the HTML document is run.
307
330
///
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
- ///
311
331
/// The script is wrapped into its own context with `(function () { /* your script here */ })();`,
312
332
/// so global variables must be assigned to `window` instead of implicitly declared.
313
333
///
314
334
/// Note that calling this function multiple times overrides previous values.
315
335
///
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
+ ///
316
349
/// # Examples
317
350
///
318
351
/// ```rust
@@ -328,13 +361,46 @@ impl<R: Runtime, C: DeserializeOwned> Builder<R, C> {
328
361
///
329
362
/// fn init<R: Runtime>() -> TauriPlugin<R> {
330
363
/// Builder::new("example")
331
- /// .js_init_script(INIT_SCRIPT.to_string() )
364
+ /// .js_init_script(INIT_SCRIPT)
332
365
/// .build()
333
366
/// }
334
367
/// ```
335
368
#[ 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
+ } ) ;
338
404
self
339
405
}
340
406
@@ -695,7 +761,7 @@ pub struct TauriPlugin<R: Runtime, C: DeserializeOwned = ()> {
695
761
app : Option < AppHandle < R > > ,
696
762
invoke_handler : Box < InvokeHandler < R > > ,
697
763
setup : Option < Box < SetupHook < R , C > > > ,
698
- js_init_script : Option < String > ,
764
+ js_init_script : Option < InitializationScript > ,
699
765
on_navigation : Box < OnNavigation < R > > ,
700
766
on_page_load : Box < OnPageLoad < R > > ,
701
767
on_window_ready : Box < OnWindowReady < R > > ,
@@ -751,6 +817,13 @@ impl<R: Runtime, C: DeserializeOwned> Plugin<R> for TauriPlugin<R, C> {
751
817
}
752
818
753
819
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 > {
754
827
self . js_init_script . clone ( )
755
828
}
756
829
@@ -842,12 +915,20 @@ impl<R: Runtime> PluginStore<R> {
842
915
}
843
916
844
917
/// 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 > {
846
919
self
847
920
. store
848
921
. 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
+ )
851
932
. collect ( )
852
933
}
853
934
0 commit comments