Skip to main content

lingxia_webview/
lib.rs

1//! Cross-platform WebView hosting layer for LingXia.
2//!
3//! This crate is strictly *generic* webview hosting: webview creation and
4//! lifecycle, navigation/scheme/event plumbing, and minimal native surface
5//! ownership required by each platform WebView runtime. It contains no
6//! product UI.
7//!
8//! On Windows, host-window grouping, chrome, panels, and app layout live in
9//! `lingxia-windows-sdk`; this crate only provides the WebView2 surface.
10
11use thiserror::Error;
12
13#[cfg(any(all(target_os = "linux", target_env = "ohos"), test))]
14mod bridge_payload;
15
16/// WebView-specific error types
17#[derive(Error, Debug, Clone, PartialEq, Eq)]
18pub enum WebViewError {
19    #[error("WebView error: {0}")]
20    WebView(String),
21
22    #[error("Invalid WebView create options: {0}")]
23    InvalidCreateOptions(String),
24
25    /// The named operation is not available on this platform's WebView runtime.
26    #[error("{0} is not supported on this platform")]
27    Unsupported(String),
28}
29
30#[derive(Error, Debug, Clone, PartialEq, Eq)]
31pub enum WebViewScriptError {
32    #[error("JavaScript error: {0}")]
33    Js(String),
34
35    #[error("JavaScript evaluation timed out")]
36    Timeout,
37
38    #[error("JavaScript evaluation unsupported: {0}")]
39    Unsupported(&'static str),
40
41    #[error("WebView destroyed during JavaScript evaluation")]
42    Destroyed,
43
44    #[error("Navigation changed during JavaScript evaluation")]
45    NavigationChanged,
46
47    #[error("Platform JavaScript evaluation error: {0}")]
48    Platform(String),
49}
50
51#[derive(Error, Debug, Clone, PartialEq, Eq)]
52pub enum WebViewInputError {
53    #[error(transparent)]
54    Script(#[from] WebViewScriptError),
55
56    #[error("Element not found: {0}")]
57    ElementNotFound(String),
58
59    #[error("Element not interactable: {0}")]
60    ElementNotInteractable(String),
61
62    #[error("Input unsupported: {0}")]
63    Unsupported(&'static str),
64
65    #[error("WebView destroyed during input handling")]
66    Destroyed,
67
68    #[error("Navigation changed during input handling")]
69    NavigationChanged,
70
71    #[error("Platform input error: {0}")]
72    Platform(String),
73}
74
75/// Log levels for WebView logging
76#[derive(Debug, Clone, Copy, PartialEq, Eq)]
77pub enum LogLevel {
78    Verbose,
79    Debug,
80    Info,
81    Warn,
82    Error,
83}
84
85mod error_page;
86/// Typed delegate events: correlated navigation lifecycle, observable state
87/// snapshots, and the canonical derived-state folds.
88pub mod events;
89mod input_helper;
90mod traits;
91/// Process-local URL callback channels for navigation handoff.
92pub mod url_callback;
93mod webview;
94
95#[cfg(target_os = "android")]
96mod android;
97
98#[cfg(any(target_os = "ios", target_os = "macos"))]
99mod apple;
100
101#[cfg(all(target_os = "linux", target_env = "ohos"))]
102mod harmony;
103
104#[cfg(any(all(target_os = "linux", target_env = "ohos"), test))]
105mod harmony_document;
106
107#[cfg(target_os = "windows")]
108mod windows;
109
110// Public exports
111// WebViewError and LogLevel are defined above
112pub use error_page::{LoadErrorPage, render_load_error_page};
113pub use events::{
114    NavigationCancellationReason, NavigationEvent, NavigationId, NavigationOutcome,
115    NavigationProgress, ObservedWebViewState, WebViewEventObserver, WebViewObservedEvent,
116    WebViewStateChange,
117};
118pub use traits::{
119    ClearSiteDataOptions, ClearSiteDataResult, ClickOptions, ContextualSchemeRequest,
120    DocumentBinding, DocumentGeneration, DocumentOutboundGate, DownloadRequest, FileChooserFile,
121    FileChooserRequest, FileChooserResponse, FillOptions, IncomingWebMessage, LoadDataRequest,
122    LoadError, LoadErrorKind, NativeWebViewId, NavigationPolicy, NavigationRequest, NetworkBody,
123    NetworkCaptureSnapshot, NetworkEntry, NewWindowPolicy, PressOptions, SchemeOutcome,
124    SchemeRequestFrame, ScrollOptions, SystemPipeReader, TrustedDocumentAdmission,
125    TrustedLoadIntent, TypeOptions, UserAgentOverride, WebMessageContext, WebMessageFrame,
126    WebMessageSource, WebMessageTransport, WebResourceBody, WebResourceResponse, WebViewController,
127    WebViewCookie, WebViewCookieSameSite, WebViewCookieSetRequest, WebViewDelegate,
128    WebViewInputController,
129};
130pub use webview::{
131    BrowserWebViewBuilder, ProxyActivation, ProxyApplyReport, ProxyApplyStatus, ProxyConfig,
132    StrictWebViewBuilder, TrustedDataLoadReservation, WebTag, WebView, WebViewBuilder,
133    WebViewCreateStage, WebViewDataMode, WebViewEvent, WebViewEventSubscription, WebViewSession,
134};
135
136/// Global website-data operations for privacy surfaces: usage counts,
137/// clear cache, clear cookies & site data.
138///
139/// Every operation here is profile-wide: all browser tabs share one browser
140/// profile (the platform's default data store), so clears affect every site,
141/// not just the current tab. On Windows, [`cache_site_count`] returns `Ok(0)`
142/// because WebView2 cannot enumerate HTTP-cache origins (clearing still
143/// works). Unsupported platforms return [`WebViewError::Unsupported`].
144pub mod data_store {
145    /// Profile-wide cookies/site-data footprint.
146    #[derive(Debug, Clone, Copy)]
147    pub struct SiteDataUsage {
148        /// Sites storing cookies or other site data.
149        pub sites: usize,
150        /// Total cookie count across all sites.
151        pub cookies: usize,
152    }
153
154    #[cfg(any(target_os = "ios", target_os = "macos"))]
155    pub use crate::apple::data_store::{
156        cache_site_count, clear_all_site_data, clear_cache, site_data_usage,
157    };
158
159    #[cfg(target_os = "windows")]
160    pub use crate::windows::data_store::{
161        cache_site_count, clear_all_site_data, clear_cache, site_data_usage,
162    };
163
164    #[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "windows")))]
165    mod unsupported {
166        use super::SiteDataUsage;
167        use crate::WebViewError;
168
169        fn err(action: &str) -> WebViewError {
170            WebViewError::Unsupported(action.to_string())
171        }
172
173        pub async fn cache_site_count() -> Result<usize, WebViewError> {
174            Err(err("cache usage query"))
175        }
176
177        pub async fn site_data_usage() -> Result<SiteDataUsage, WebViewError> {
178            Err(err("site data usage query"))
179        }
180
181        pub async fn clear_cache(_since_unix_ms: Option<u64>) -> Result<(), WebViewError> {
182            Err(err("clear cache"))
183        }
184
185        pub async fn clear_all_site_data(_since_unix_ms: Option<u64>) -> Result<(), WebViewError> {
186            Err(err("clear cookies & site data"))
187        }
188    }
189    #[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "windows")))]
190    pub use unsupported::*;
191}
192
193/// Runtime-scoped APIs (instance lookup/destruction, proxy state).
194pub mod runtime {
195    use std::sync::Arc;
196
197    use crate::webview;
198    use crate::{ProxyApplyReport, ProxyConfig, WebTag, WebView, WebViewError};
199
200    pub fn find_webview(webtag: &WebTag) -> Option<Arc<WebView>> {
201        webview::find_webview(webtag)
202    }
203
204    pub fn list_webviews() -> Vec<WebTag> {
205        webview::list_webviews()
206    }
207
208    /// Destroy whichever WebView is currently registered for this logical tag.
209    ///
210    /// Callers which own a concrete [`WebView`] should prefer
211    /// [`destroy_webview_if_matches`] so delayed teardown cannot destroy a
212    /// replacement which reused the tag.
213    pub fn destroy_current_webview(webtag: &WebTag) {
214        webview::destroy_current_webview(webtag);
215    }
216
217    pub fn destroy_webview_if_matches(webtag: &WebTag, expected: &Arc<WebView>) -> bool {
218        webview::destroy_webview_if_matches(webtag, expected)
219    }
220
221    pub fn configure_proxy_for_new_webviews(
222        config: Option<ProxyConfig>,
223    ) -> Result<(), WebViewError> {
224        webview::configure_proxy_for_new_webviews(config)
225    }
226
227    pub fn apply_proxy_to_current_runtime(
228        config: Option<ProxyConfig>,
229    ) -> Result<ProxyApplyReport, WebViewError> {
230        webview::apply_proxy_to_current_runtime(config)
231    }
232
233    pub fn configured_proxy_for_new_webviews() -> Option<ProxyConfig> {
234        webview::configured_proxy_for_new_webviews()
235    }
236}
237
238/// Platform-specific APIs used by SDK/FFI integration layers.
239pub mod platform {
240    #[cfg(target_os = "android")]
241    pub mod android {
242        pub use crate::android::{initialize_jni, with_env};
243    }
244
245    #[cfg(any(target_os = "ios", target_os = "macos"))]
246    pub mod apple {
247        #[cfg(target_os = "macos")]
248        pub use crate::apple::toggle_webview_devtools_by_swift_ptr;
249        pub use crate::apple::{
250            BRIDGE_DOWNSTREAM_CSP_SOURCE, BRIDGE_DOWNSTREAM_URL,
251            configure_user_agent_override_for_webviews,
252        };
253    }
254
255    #[cfg(all(target_os = "linux", target_env = "ohos"))]
256    pub mod harmony {
257        pub use crate::harmony::{
258            check_navigation_policy, complete_pending_screenshot_request, notify_webview_state,
259            on_document_commit, on_file_chooser_requested, on_page_begin, on_page_end,
260            on_render_exited, schemehandler::register_custom_schemes, tsfn,
261            webview_controller_created, webview_controller_destroyed,
262        };
263
264        #[doc(hidden)]
265        pub fn on_load_error(
266            webtag: &str,
267            native_generation: &str,
268            page_epoch: u64,
269            url: &str,
270            error_code: i32,
271            description: &str,
272        ) {
273            crate::harmony::on_load_error(
274                webtag,
275                native_generation,
276                page_epoch,
277                url,
278                error_code,
279                description,
280            );
281        }
282
283        #[doc(hidden)]
284        pub fn on_download_start(
285            webtag_str: &str,
286            native_view_token: &str,
287            url: &str,
288            user_agent: &str,
289            content_disposition: &str,
290            mime_type: &str,
291            content_length: i64,
292        ) -> bool {
293            crate::harmony::on_download_start(
294                webtag_str,
295                native_view_token,
296                url,
297                user_agent,
298                content_disposition,
299                mime_type,
300                content_length,
301            )
302        }
303    }
304
305    #[cfg(target_os = "windows")]
306    pub mod windows {
307        pub use crate::windows::{
308            CompositionSurfacePixels, IslandPointerPhase, IslandVideoFrame, IslandVisualSpec,
309            SYNTHETIC_MOUSE_WPARAM_MARKER, WindowsBrowserEmulationProfile,
310            WindowsPreferredColorScheme, WindowsWebViewHandler, WindowsWebViewNativeView,
311            WindowsWebViewNativeViewHost, capture_composition_surface_bgra,
312            clear_windows_lxapp_preferred_color_scheme, find_composition_surface_hwnd,
313            find_webview_handler, queue_island_visuals, queued_island_visuals,
314            set_island_pointer_filter, set_webview_composition_hosting,
315            set_webview_devtools_enabled, set_webview_native_view_host, set_webview_user_data_dir,
316            set_windows_browser_emulation_profile_for_new_webviews,
317            set_windows_context_menu_refresh_provider, set_windows_lxapp_preferred_color_scheme,
318            set_windows_preferred_color_scheme_for_new_webviews,
319            webview_composition_hosting_enabled,
320        };
321    }
322}