Skip to content

Commit b27be06

Browse files
feat: add eval_with_callback to Webview and WebviewWindow (#14925)
* feat: add `eval_with_callback` to Webview and WebviewWindow * docs: fix eval_with_callback docs and add change file --------- Co-authored-by: Tony <68118705+Legend-Master@users.noreply.github.com>
1 parent cdf5276 commit b27be06

6 files changed

Lines changed: 121 additions & 0 deletions

File tree

.changes/eval-with-callback.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'tauri': 'minor:feat'
3+
'tauri-runtime': 'minor:feat'
4+
'tauri-runtime-wry': 'minor:feat'
5+
---
6+
7+
Add `eval_with_callback` to the Tauri webview APIs and runtime dispatch layers.

crates/tauri-runtime-wry/src/lib.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1475,6 +1475,15 @@ pub enum WebviewMessage {
14751475
EvaluateScript(String),
14761476
#[cfg(all(feature = "tracing", not(target_os = "android")))]
14771477
EvaluateScript(String, Sender<()>, tracing::Span),
1478+
#[cfg(not(all(feature = "tracing", not(target_os = "android"))))]
1479+
EvaluateScriptWithCallback(String, Box<dyn Fn(String) + Send + 'static>),
1480+
#[cfg(all(feature = "tracing", not(target_os = "android")))]
1481+
EvaluateScriptWithCallback(
1482+
String,
1483+
Box<dyn Fn(String) + Send + 'static>,
1484+
Sender<()>,
1485+
tracing::Span,
1486+
),
14781487
CookiesForUrl(Url, Sender<Result<Vec<tauri_runtime::Cookie<'static>>>>),
14791488
Cookies(Sender<Result<Vec<tauri_runtime::Cookie<'static>>>>),
14801489
SetCookie(tauri_runtime::Cookie<'static>),
@@ -1830,6 +1839,46 @@ impl<T: UserEvent> WebviewDispatch<T> for WryWebviewDispatcher<T> {
18301839
)
18311840
}
18321841

1842+
#[cfg(all(feature = "tracing", not(target_os = "android")))]
1843+
fn eval_script_with_callback<S: Into<String>>(
1844+
&self,
1845+
script: S,
1846+
callback: impl Fn(String) + Send + 'static,
1847+
) -> Result<()> {
1848+
// use a channel so the EvaluateScript task uses the current span as parent
1849+
let (tx, rx) = channel();
1850+
getter!(
1851+
self,
1852+
rx,
1853+
Message::Webview(
1854+
*self.window_id.lock().unwrap(),
1855+
self.webview_id,
1856+
WebviewMessage::EvaluateScriptWithCallback(
1857+
script.into(),
1858+
Box::new(callback),
1859+
tx,
1860+
tracing::Span::current(),
1861+
),
1862+
)
1863+
)
1864+
}
1865+
1866+
#[cfg(not(all(feature = "tracing", not(target_os = "android"))))]
1867+
fn eval_script_with_callback<S: Into<String>>(
1868+
&self,
1869+
script: S,
1870+
callback: impl Fn(String) + Send + 'static,
1871+
) -> Result<()> {
1872+
send_user_message(
1873+
&self.context,
1874+
Message::Webview(
1875+
*self.window_id.lock().unwrap(),
1876+
self.webview_id,
1877+
WebviewMessage::EvaluateScriptWithCallback(script.into(), Box::new(callback)),
1878+
),
1879+
)
1880+
}
1881+
18331882
fn set_zoom(&self, scale_factor: f64) -> Result<()> {
18341883
send_user_message(
18351884
&self.context,
@@ -3712,6 +3761,20 @@ fn handle_user_message<T: UserEvent>(
37123761
log::error!("{e}");
37133762
}
37143763
}
3764+
#[cfg(all(feature = "tracing", not(target_os = "android")))]
3765+
WebviewMessage::EvaluateScriptWithCallback(script, callback, tx, span) => {
3766+
let _span = span.entered();
3767+
if let Err(e) = webview.evaluate_script_with_callback(&script, callback) {
3768+
log::error!("{e}");
3769+
}
3770+
tx.send(()).unwrap();
3771+
}
3772+
#[cfg(not(all(feature = "tracing", not(target_os = "android"))))]
3773+
WebviewMessage::EvaluateScriptWithCallback(script, callback) => {
3774+
if let Err(e) = webview.evaluate_script_with_callback(&script, callback) {
3775+
log::error!("{e}");
3776+
}
3777+
}
37153778
WebviewMessage::Navigate(url) => {
37163779
if let Err(e) = webview.load_url(url.as_str()) {
37173780
log::error!("failed to navigate to url {}: {}", url, e);

crates/tauri-runtime/src/lib.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,16 @@ pub trait WebviewDispatch<T: UserEvent>: Debug + Clone + Send + Sync + Sized + '
590590
/// Executes javascript on the window this [`WindowDispatch`] represents.
591591
fn eval_script<S: Into<String>>(&self, script: S) -> Result<()>;
592592

593+
/// Evaluate JavaScript with callback function on the webview this [`WebviewDispatch`] represents.
594+
/// The evaluation result will be serialized into a JSON string and passed to the callback function.
595+
///
596+
/// Exception is ignored because of the limitation on Windows. You can catch it yourself and return as string as a workaround.
597+
fn eval_script_with_callback<S: Into<String>>(
598+
&self,
599+
script: S,
600+
callback: impl Fn(String) + Send + 'static,
601+
) -> Result<()>;
602+
593603
/// Moves the webview to the given window.
594604
fn reparent(&self, window_id: WindowId) -> Result<()>;
595605

crates/tauri/src/test/mock_runtime.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,19 @@ impl<T: UserEvent> WebviewDispatch<T> for MockWebviewDispatcher {
593593
Ok(())
594594
}
595595

596+
fn eval_script_with_callback<S: Into<String>>(
597+
&self,
598+
script: S,
599+
callback: impl Fn(String) + Send + 'static,
600+
) -> Result<()> {
601+
self
602+
.last_evaluated_script
603+
.lock()
604+
.unwrap()
605+
.replace(script.into());
606+
Ok(())
607+
}
608+
596609
fn url(&self) -> Result<String> {
597610
Ok(self.url.lock().unwrap().clone())
598611
}

crates/tauri/src/webview/mod.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1896,6 +1896,22 @@ tauri::Builder::default()
18961896
.map_err(Into::into)
18971897
}
18981898

1899+
/// Evaluate JavaScript with callback function on this webview.
1900+
/// The evaluation result will be serialized into a JSON string and passed to the callback function.
1901+
///
1902+
/// Exception is ignored because of the limitation on Windows. You can catch it yourself and return as string as a workaround.
1903+
pub fn eval_with_callback(
1904+
&self,
1905+
js: impl Into<String>,
1906+
callback: impl Fn(String) + Send + 'static,
1907+
) -> crate::Result<()> {
1908+
self
1909+
.webview
1910+
.dispatcher
1911+
.eval_script_with_callback(js.into(), callback)
1912+
.map_err(Into::into)
1913+
}
1914+
18991915
/// Register a JS event listener and return its identifier.
19001916
pub(crate) fn listen_js(
19011917
&self,

crates/tauri/src/webview/webview_window.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2363,6 +2363,18 @@ impl<R: Runtime> WebviewWindow<R> {
23632363
self.webview.eval(js)
23642364
}
23652365

2366+
/// Evaluate JavaScript with callback function on this webview.
2367+
/// The evaluation result will be serialized into a JSON string and passed to the callback function.
2368+
///
2369+
/// Exception is ignored because of the limitation on Windows. You can catch it yourself and return as string as a workaround.
2370+
pub fn eval_with_callback(
2371+
&self,
2372+
js: impl Into<String>,
2373+
callback: impl Fn(String) + Send + 'static,
2374+
) -> crate::Result<()> {
2375+
self.webview.eval_with_callback(js, callback)
2376+
}
2377+
23662378
/// Opens the developer tools window (Web Inspector).
23672379
/// The devtools is only enabled on debug builds or with the `devtools` feature flag.
23682380
///

0 commit comments

Comments
 (0)