diff --git a/apps/app/src/api/ads.rs b/apps/app/src/api/ads.rs index 40d00ce76..7dbcb4455 100644 --- a/apps/app/src/api/ads.rs +++ b/apps/app/src/api/ads.rs @@ -25,7 +25,11 @@ pub fn init() -> TauriPlugin { malicious_origins: HashSet::new(), })); - // We refresh the ads window every 5 minutes for performance + // We refresh the ads window every 5 minutes to mitigate memory leak issues. + // While this loop doesn't include explicit checks to see if the window is still + // visible when we refresh, the Aditude wrapper will not make any ad requests + // unless Chromium reports the page as visible. The refresh does not reset the + // visibility state. let app = app.clone(); tauri::async_runtime::spawn(async move { loop { @@ -92,14 +96,21 @@ pub async fn init_ads_window( } if let Ok((position, size)) = get_webview_position(&app, dpr) { - if let Some(webview) = app.webviews().get("ads-window") { + let webview = if let Some(webview) = app.webviews().get("ads-window") { + // set both the `hide`/`show` state and `position`, + // to ensure that the webview is actually shown/hidden if state.shown { - let _ = webview.set_position(position); - let _ = webview.set_size(size); + webview.show().ok(); + webview.set_position(position).ok(); + webview.set_size(size).ok(); } else { - let _ = - webview.set_position(PhysicalPosition::new(-1000, -1000)); + webview.hide().ok(); + webview + .set_position(PhysicalPosition::new(-1000, -1000)) + .ok(); } + + Some(webview.clone()) } else if let Some(window) = app.get_window("main") { let webview = window.add_child( tauri::webview::WebviewBuilder::new( @@ -109,10 +120,16 @@ pub async fn init_ads_window( ), ) .initialization_script_for_all_frames(include_str!("ads-init.js")) + // We use a standard Chrome user agent for compatibility with our ad provider, + // since Tauri is not recognized by ad providers by default. + // Aditude has separately informed SSPs and IVT vendors that this traffic + // originates from a desktop app. .user_agent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36") .zoom_hotkeys_enabled(false) .transparent(true) .on_new_window(|_, _| tauri::webview::NewWindowResponse::Deny), + // set both the `hide`/`show` state and `position`, + // to ensure that the webview is actually shown/hidden if state.shown { position } else { @@ -121,6 +138,12 @@ pub async fn init_ads_window( size, )?; + if state.shown { + webview.show().ok(); + } else { + webview.hide().ok(); + } + webview.with_webview(#[allow(unused_variables)] |webview2| { #[cfg(windows)] { @@ -137,7 +160,67 @@ pub async fn init_ads_window( unsafe { webview2_8.SetIsMuted(true) }.ok(); } })?; - } + + Some(webview) + } else { + None + }; + + let Some(webview) = webview.clone() else { + return Ok(()); + }; + + // tauri::async_runtime::spawn(async move { + // loop { + // webview.with_webview(|wv| { + // #[cfg(windows)] + // { + // use webview2_com::ExecuteScriptCompletedHandler; + + // let core_webview2 = unsafe { + // webview.controller().CoreWebView2().unwrap() + // }; + + // let handler = ExecuteScriptCompletedHandler::create(Box::new( + // move |hr: windows_core::Result<()>, result: String| { + // if hr.is_ok() { + // let hidden: bool = serde_json::from_str(&result).unwrap_or(true); + // tracing::error!("!! ads wv hidden? {}", hidden); + // } + // Ok(()) + // }, + // ) as Box<_>); + + // unsafe { + // let _ = core_webview2.ExecuteScript( + // windows_core::w!("document.hidden"), + // &handler, + // ); + // } + // } + + // #[cfg(not(windows))] + // { + // use webkit2gtk::WebViewExt; + + // wv.inner().evaluate_javascript( + // "document.hidden", + // None, + // None, + // None::<&webkit2gtk::gio::Cancellable>, + // |result| { + // use javascriptcore::ValueExt; + + // let hidden = result.map(|v| v.to_boolean()); + // tracing::error!("!! ads wv hidden? {hidden:?}"); + // }, + // ); + // } + // }); + + // tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; + // } + // }); } Ok(()) @@ -161,8 +244,11 @@ pub async fn show_ads_window( if state.shown { let (position, size) = get_webview_position(&app, dpr)?; - let _ = webview.set_size(size); - let _ = webview.set_position(position); + // set both the `hide`/`show` state and `position`, + // to ensure that the webview is actually shown/hidden + webview.set_size(size).ok(); + webview.set_position(position).ok(); + webview.show().ok(); } } @@ -184,7 +270,12 @@ pub async fn hide_ads_window( state.modal_shown = true; } - let _ = webview.set_position(PhysicalPosition::new(-1000, -1000)); + // set both the `hide`/`show` state and `position`, + // to ensure that the webview is actually shown/hidden + webview + .set_position(PhysicalPosition::new(-1000, -1000)) + .ok(); + webview.hide().ok(); } Ok(())