tauri_plugin_cef_webview/lib.rs
1//! Embed native child webviews in a Tauri application and control them from
2//! the frontend with a plain `<webview>` element.
3
4mod commands;
5mod frames;
6#[cfg(feature = "offscreen")]
7mod offscreen;
8mod registry;
9mod scripts;
10
11pub use registry::{CefWebview, Registry};
12
13use tauri::{
14 plugin::{Builder as PluginBuilder, TauriPlugin},
15 Manager, Runtime,
16};
17
18/// Installed into every application page so `<webview>` works without imports.
19/// Registered as a plugin initialization script, so it runs before any page
20/// script in every webview, including windows created from the app config.
21const HOST_RUNTIME: &str = include_str!("element.js.inc");
22
23/// Plugin configuration.
24#[derive(Clone, Debug, Default)]
25pub struct Config {
26 /// JavaScript injected into every child webview before page scripts run.
27 pub js: Vec<String>,
28 /// CSS injected into every child webview.
29 pub css: Vec<String>,
30 /// Create child webviews off-screen and paint them into the host page.
31 ///
32 /// Requires `runtime(cef_runtime())` from this crate and the `offscreen`
33 /// feature; falls back to native child webviews otherwise.
34 pub offscreen: bool,
35}
36
37impl Config {
38 /// Adds a JavaScript snippet applied to every child webview.
39 pub fn js(mut self, script: impl Into<String>) -> Self {
40 self.js.push(script.into());
41 self
42 }
43
44 /// Adds a stylesheet applied to every child webview.
45 pub fn css(mut self, css: impl Into<String>) -> Self {
46 self.css.push(css.into());
47 self
48 }
49
50 /// Renders child webviews into the host page instead of native child views.
51 pub fn offscreen(mut self, offscreen: bool) -> Self {
52 self.offscreen = offscreen;
53 self
54 }
55}
56
57/// Initializes the plugin with the default configuration.
58pub fn init<R: Runtime>() -> TauriPlugin<R> {
59 init_with(Config::default())
60}
61
62/// Initializes the plugin with a custom configuration.
63pub fn init_with<R: Runtime>(config: Config) -> TauriPlugin<R> {
64 PluginBuilder::new("cef-webview")
65 .initialization_script(HOST_RUNTIME)
66 .invoke_handler(tauri::generate_handler![
67 commands::create,
68 commands::set_rect,
69 commands::set_visible,
70 commands::destroy,
71 commands::eval,
72 commands::insert_css,
73 commands::remove_inserted_css,
74 commands::navigate,
75 commands::reload,
76 commands::open_devtools,
77 commands::call,
78 commands::frame,
79 ])
80 .setup(move |app, _api| {
81 app.manage(Registry::<R>::new(config));
82 Ok(())
83 })
84 .build()
85}
86
87/// Access the plugin registry from a Tauri app handle.
88pub trait CefWebviewExt<R: Runtime> {
89 /// Returns the plugin registry, which exposes [`Registry::get`].
90 fn cef_webviews(&self) -> tauri::State<'_, Registry<R>>;
91}
92
93impl<R: Runtime, M: Manager<R>> CefWebviewExt<R> for M {
94 fn cef_webviews(&self) -> tauri::State<'_, Registry<R>> {
95 self.state::<Registry<R>>()
96 }
97}
98
99/// Returns the CEF runtime with windowless rendering enabled, required by
100/// [`Config::offscreen`].
101///
102/// ```text
103/// # use tauri::Manager;
104/// tauri::Builder::default()
105/// .runtime(tauri_plugin_cef_webview::cef_runtime())
106/// .plugin(tauri_plugin_cef_webview::init_with(
107/// tauri_plugin_cef_webview::Config::default().offscreen(true),
108/// ))
109/// # .run(tauri::generate_context!())
110/// # .unwrap();
111/// ```
112#[cfg(feature = "offscreen")]
113pub fn cef_runtime() -> tauri_runtime_cef::Cef {
114 use tauri_runtime_cef::Cef;
115 Cef::default().with_settings(|settings| {
116 settings.windowless_rendering_enabled = 1;
117 })
118}