Skip to main content

lingxia_browser/
lib.rs

1mod automation;
2mod chooser;
3mod downloads;
4mod internal_pages;
5mod policy;
6mod tabs;
7mod types;
8mod webview;
9
10pub use lingxia_webview::{WebViewCookie, WebViewCookieSameSite, WebViewCookieSetRequest};
11pub use policy::{extract_url_scheme, is_lingxia_startup_url};
12use std::sync::Arc;
13use std::time::Duration;
14pub use types::{
15    BrowserAddressAction, BrowserAddressInputContext, BrowserAddressInputError,
16    BrowserAddressInputRequest, BrowserAddressInputResponse, BrowserAddressInputTrigger,
17    BrowserAddressNavigation, BrowserAddressState, BrowserAddressSuggestion,
18    BrowserAddressValueKind, BrowserAutomationError, BrowserElementInfo, BrowserNativeInputHost,
19    BrowserNavigationPolicyDecision, BrowserNavigationPolicyRequest,
20    BrowserNavigationPolicyResponse, BrowserNavigationTarget, BrowserRect, BrowserTabInfo,
21    BrowserWaitCondition, BrowserWaitResult,
22};
23
24pub use lxapp::LxAppError;
25
26pub const BUILTIN_BROWSER_APPID: &str = "app.lingxia.browser";
27
28pub fn classify_navigation(
29    request: BrowserNavigationPolicyRequest,
30) -> BrowserNavigationPolicyResponse {
31    policy::handle_browser_navigation_policy(request)
32}
33
34pub fn classify_navigation_json(request_json: &str) -> Option<String> {
35    policy::handle_browser_navigation_policy_json(request_json)
36}
37
38#[doc(hidden)]
39pub fn register_startup_page_script(js: impl Into<String>) {
40    internal_pages::register_browser_startup_page_script(js);
41}
42
43#[doc(hidden)]
44pub fn install_runtime() {
45    lxapp::register_page_resolver(internal_pages::browser_logic_page_path_for_tab_path);
46    lingxia_transfer::runtime::register_browser_tab_path_resolver(tabs::browser_tab_path_for_id);
47    lingxia_transfer::runtime::register_browser_retry_handler(
48        downloads::retry_browser_owned_download,
49    );
50}
51
52#[doc(hidden)]
53pub fn register_internal_page(
54    route: impl Into<String>,
55    entry_asset: impl Into<String>,
56) -> Result<(), LxAppError> {
57    internal_pages::register_browser_internal_page(route, entry_asset)
58}
59
60pub fn open(url: &str, tab_id: Option<&str>) -> Result<String, LxAppError> {
61    tabs::open_internal_browser_tab(url, tab_id)
62}
63
64pub fn open_for_app(
65    appid: &str,
66    session_id: u64,
67    url: &str,
68    tab_id: Option<&str>,
69) -> Result<String, LxAppError> {
70    tabs::open_internal_browser_tab_for_owner(appid, session_id, url, tab_id, false)
71}
72
73/// Open a standalone browser tab (no tab strip) for a docked aside browser.
74/// New-window requests from this tab load inline in the same WebView rather
75/// than spawning a new main-area tab.
76pub fn open_standalone_for_app(
77    appid: &str,
78    session_id: u64,
79    url: &str,
80    tab_id: Option<&str>,
81) -> Result<String, LxAppError> {
82    tabs::open_internal_browser_tab_for_owner(appid, session_id, url, tab_id, true)
83}
84
85pub fn close(tab_id: &str) -> Result<(), LxAppError> {
86    tabs::close_browser_tab(tab_id)
87}
88
89/// Discard a tab's WebView to free memory while keeping its sidebar entry.
90pub fn discard(tab_id: &str) -> Result<(), LxAppError> {
91    tabs::discard_browser_tab(tab_id)
92}
93
94/// Recreate a discarded tab's WebView, reload its URL, and activate it.
95pub fn reactivate(tab_id: &str) -> Result<(), LxAppError> {
96    tabs::reactivate_browser_tab(tab_id)
97}
98
99/// Sync the Rust-side active tab when the SDK switches to an already-live tab.
100pub fn mark_active(tab_id: &str) {
101    tabs::mark_browser_tab_active(tab_id)
102}
103
104pub fn tabs() -> Vec<BrowserTabInfo> {
105    tabs::browser_tabs()
106}
107
108pub fn current_tab() -> Option<BrowserTabInfo> {
109    tabs::browser_current_tab()
110}
111
112pub fn activate(tab_id: &str) -> Result<BrowserTabInfo, BrowserAutomationError> {
113    tabs::browser_activate_tab(tab_id)
114}
115
116/// Registers a process-wide observer invoked whenever the browser tab set
117/// or tab metadata changes: tab opened/closed, active tab switched, or a
118/// tab's URL/title updated. Intended for shell UIs that mirror the tab
119/// list (e.g. sidebar tab rows); the previous handler (if any) is replaced.
120///
121/// The callback may fire from arbitrary runtime threads (webview UI
122/// threads included) and must not block; query [`tabs`]/[`current_tab`]
123/// from it to read the new state.
124pub fn set_tabs_changed_handler(handler: Arc<dyn Fn() + Send + Sync>) {
125    tabs::set_tabs_changed_handler(handler);
126}
127
128/// PNG-encoded favicon of `tab_id`'s current page, if the platform webview
129/// reported one (see `WebViewDelegate::on_favicon_changed`). Kept out of
130/// [`BrowserTabInfo`] so the serialized tab projection stays byte-free;
131/// shell sidebars query it per tab when mirroring the tab list.
132pub fn tab_favicon(tab_id: &str) -> Option<Arc<Vec<u8>>> {
133    tabs::browser_tab_favicon(tab_id)
134}
135
136pub fn register_native_input_host(host: Arc<dyn BrowserNativeInputHost>) -> bool {
137    automation::register_native_input_host(host)
138}
139
140pub async fn evaluate_javascript(
141    tab_id: &str,
142    js: &str,
143) -> Result<serde_json::Value, BrowserAutomationError> {
144    automation::browser_evaluate_javascript(tab_id, js).await
145}
146
147pub async fn take_screenshot(tab_id: &str) -> Result<Vec<u8>, BrowserAutomationError> {
148    automation::browser_take_screenshot(tab_id).await
149}
150
151pub async fn current_url(tab_id: &str) -> Result<Option<String>, BrowserAutomationError> {
152    automation::browser_current_url(tab_id).await
153}
154
155pub fn reload(tab_id: &str) -> Result<(), BrowserAutomationError> {
156    automation::browser_reload(tab_id)
157}
158
159pub fn go_back(tab_id: &str) -> Result<(), BrowserAutomationError> {
160    automation::browser_go_back(tab_id)
161}
162
163pub fn go_forward(tab_id: &str) -> Result<(), BrowserAutomationError> {
164    automation::browser_go_forward(tab_id)
165}
166
167pub async fn list_cookies(tab_id: &str) -> Result<Vec<WebViewCookie>, BrowserAutomationError> {
168    automation::browser_list_cookies(tab_id).await
169}
170
171pub async fn list_all_cookies(tab_id: &str) -> Result<Vec<WebViewCookie>, BrowserAutomationError> {
172    automation::browser_list_all_cookies(tab_id).await
173}
174
175pub async fn set_cookie(
176    tab_id: &str,
177    request: WebViewCookieSetRequest,
178) -> Result<(), BrowserAutomationError> {
179    automation::browser_set_cookie(tab_id, request).await
180}
181
182pub async fn delete_cookie(
183    tab_id: &str,
184    name: &str,
185    domain: &str,
186    path: &str,
187) -> Result<(), BrowserAutomationError> {
188    automation::browser_delete_cookie(tab_id, name, domain, path).await
189}
190
191pub async fn clear_cookies(tab_id: &str) -> Result<(), BrowserAutomationError> {
192    automation::browser_clear_cookies(tab_id).await
193}
194
195pub async fn query(
196    tab_id: &str,
197    selector: &str,
198) -> Result<BrowserElementInfo, BrowserAutomationError> {
199    automation::browser_query(tab_id, selector).await
200}
201
202pub async fn query_with_max_text(
203    tab_id: &str,
204    selector: &str,
205    max_text_chars: Option<usize>,
206) -> Result<BrowserElementInfo, BrowserAutomationError> {
207    automation::browser_query_with_max_text(tab_id, selector, max_text_chars).await
208}
209
210pub async fn wait(
211    tab_id: &str,
212    condition: BrowserWaitCondition,
213    timeout: Duration,
214) -> Result<BrowserWaitResult, BrowserAutomationError> {
215    automation::browser_wait(tab_id, condition, timeout).await
216}
217
218pub async fn wait_for_url(
219    tab_id: &str,
220    url: &str,
221    timeout: Duration,
222) -> Result<BrowserWaitResult, BrowserAutomationError> {
223    automation::browser_wait_for_url(tab_id, url, timeout).await
224}
225
226pub async fn wait_for_url_contains(
227    tab_id: &str,
228    text: &str,
229    timeout: Duration,
230) -> Result<BrowserWaitResult, BrowserAutomationError> {
231    automation::browser_wait_for_url_contains(tab_id, text, timeout).await
232}
233
234pub async fn wait_for_navigation(
235    tab_id: &str,
236    timeout: Duration,
237    wait_until_complete: bool,
238) -> Result<BrowserWaitResult, BrowserAutomationError> {
239    automation::browser_wait_for_navigation(tab_id, timeout, wait_until_complete).await
240}
241
242pub async fn click(tab_id: &str, selector: &str) -> Result<(), BrowserAutomationError> {
243    automation::browser_click(tab_id, selector).await
244}
245
246pub async fn type_text(
247    tab_id: &str,
248    selector: &str,
249    text: &str,
250) -> Result<(), BrowserAutomationError> {
251    automation::browser_type_text(tab_id, selector, text).await
252}
253
254pub async fn fill(tab_id: &str, selector: &str, text: &str) -> Result<(), BrowserAutomationError> {
255    automation::browser_fill(tab_id, selector, text).await
256}
257
258pub async fn press(tab_id: &str, key: &str) -> Result<(), BrowserAutomationError> {
259    automation::browser_press(tab_id, key).await
260}
261
262pub async fn scroll(tab_id: &str, dx: f64, dy: f64) -> Result<(), BrowserAutomationError> {
263    automation::browser_scroll(tab_id, dx, dy).await
264}
265
266pub async fn scroll_to(tab_id: &str, selector: &str) -> Result<(), BrowserAutomationError> {
267    automation::browser_scroll_to(tab_id, selector).await
268}
269
270pub fn tab_path(tab_id: &str) -> String {
271    tabs::browser_tab_path_for_id(tab_id)
272}
273
274pub fn update_tab(tab_id: &str, current_url: Option<&str>, title: Option<&str>) -> bool {
275    tabs::browser_update_tab_info(tab_id, current_url, title)
276}
277
278pub fn start_download(
279    tab_id: &str,
280    url: &str,
281    user_agent: Option<&str>,
282    suggested_filename: Option<&str>,
283    source_page_url: Option<&str>,
284    cookie: Option<&str>,
285) -> Result<(), LxAppError> {
286    downloads::start_native_browser_download(
287        tab_id,
288        url,
289        user_agent,
290        suggested_filename,
291        source_page_url,
292        cookie,
293    )
294}
295
296#[doc(hidden)]
297pub fn register_bundled_app() {
298    tabs::register_builtin_browser_host();
299}
300
301#[doc(hidden)]
302pub fn warmup() {
303    if let Err(err) = internal_pages::warmup_builtin_browser_runtime() {
304        lxapp::warn!("[InternalBrowser] warmup failed: {}", err);
305    }
306}