๐Ÿ“ฆ tauri-apps / wry

Cross-platform WebView library in Rust for Tauri.

โ˜… 4.6k stars โ‘‚ 401 forks ๐Ÿ‘ 4.6k watching โš–๏ธ Apache License 2.0
๐Ÿ“ฅ Clone https://github.com/tauri-apps/wry.git
HTTPS git clone https://github.com/tauri-apps/wry.git
SSH git clone git@github.com:tauri-apps/wry.git
CLI gh repo clone tauri-apps/wry
github-actions[bot] github-actions[bot] apply version updates (#1656) 9fa99b1 1 days ago ๐Ÿ“ History
๐Ÿ“‚ dev View all commits โ†’
๐Ÿ“ .cargo
๐Ÿ“ .changes
๐Ÿ“ .github
๐Ÿ“ audits
๐Ÿ“ bench
๐Ÿ“ examples
๐Ÿ“ src
๐Ÿ“„ .gitignore
๐Ÿ“„ .license_template
๐Ÿ“„ build.rs
๐Ÿ“„ Cargo.lock
๐Ÿ“„ Cargo.toml
๐Ÿ“„ CHANGELOG.md
๐Ÿ“„ LICENSE-APACHE
๐Ÿ“„ LICENSE-MIT
๐Ÿ“„ LICENSE.spdx
๐Ÿ“„ MOBILE.md
๐Ÿ“„ README.md
๐Ÿ“„ renovate.json
๐Ÿ“„ rustfmt.toml
๐Ÿ“„ SECURITY.md
๐Ÿ“„ wry-logo.svg
๐Ÿ“„ README.md

WRY Webview Rendering library

License Chat Server website https://good-labs.github.io/greater-good-affirmation/assets/images/badge.svg support

Wry is a cross-platform WebView rendering library.

The webview requires a running event loop and a window type that implements [HasWindowHandle], or a gtk container widget if you need to support X11 and Wayland. You can use a windowing library like [tao] or [winit].

Examples

This example leverages the [HasWindowHandle] and supports Windows, macOS, iOS, Android and Linux (X11 Only). See the following example using [winit]:

#[derive(Default)]
struct App {
  window: Option<Window>,
  webview: Option<wry::WebView>,
}

impl ApplicationHandler for App {
  fn resumed(&mut self, event_loop: &ActiveEventLoop) {
    let window = event_loop.create_window(Window::default_attributes()).unwrap();
    let webview = WebViewBuilder::new()
      .with_url("https://tauri.app")
      .build(&window)
      .unwrap();

    self.window = Some(window);
    self.webview = Some(webview);
  }

  fn window_event(&mut self, _event_loop: &ActiveEventLoop, _window_id: WindowId, event: WindowEvent) {}
}

let event_loop = EventLoop::new().unwrap();
let mut app = App::default();
event_loop.run_app(&mut app).unwrap();

If you also want to support Wayland too, then we recommend you use [WebViewBuilderExtUnix::new_gtk] on Linux. See the following example using [tao]:

let event_loop = EventLoop::new();
let window = WindowBuilder::new().build(&event_loop).unwrap();

let builder = WebViewBuilder::new().with_url("https://tauri.app");

#[cfg(not(target_os = "linux"))]
let webview = builder.build(&window).unwrap();
#[cfg(target_os = "linux")]
let webview = builder.build_gtk(window.gtk_window()).unwrap();

Child webviews

You can use [WebView::new_as_child] or [WebViewBuilder::new_as_child] to create the webview as a child inside another window. This is supported on macOS, Windows and Linux (X11 Only).

#[derive(Default)]
struct App {
  window: Option<Window>,
  webview: Option<wry::WebView>,
}

impl ApplicationHandler for App {
  fn resumed(&mut self, event_loop: &ActiveEventLoop) {
    let window = event_loop.create_window(Window::default_attributes()).unwrap();
    let webview = WebViewBuilder::new()
      .with_url("https://tauri.app")
      .with_bounds(Rect {
        position: LogicalPosition::new(100, 100).into(),
        size: LogicalSize::new(200, 200).into(),
      })
      .build_as_child(&window)
      .unwrap();

    self.window = Some(window);
    self.webview = Some(webview);
  }

  fn window_event(&mut self, _event_loop: &ActiveEventLoop, _window_id: WindowId, event: WindowEvent) {}
}

let event_loop = EventLoop::new().unwrap();
let mut app = App::default();
event_loop.run_app(&mut app).unwrap();

If you want to support X11 and Wayland at the same time, we recommend using [WebViewExtUnix::new_gtk] or [WebViewBuilderExtUnix::new_gtk] with [gtk::Fixed].

let event_loop = EventLoop::new();
let window = WindowBuilder::new().build(&event_loop).unwrap();

let builder = WebViewBuilder::new()
  .with_url("https://tauri.app")
  .with_bounds(Rect {
    position: LogicalPosition::new(100, 100).into(),
    size: LogicalSize::new(200, 200).into(),
  });

#[cfg(not(target_os = "linux"))]
let webview = builder.build_as_child(&window).unwrap();
#[cfg(target_os = "linux")]
let webview = {
  # use gtk::prelude::*;
  let vbox = window.default_vbox().unwrap(); // tao adds a gtk::Box by default
  let fixed = gtk::Fixed::new();
  fixed.show_all();
  vbox.pack_start(&fixed, true, true, 0);
  builder.build_gtk(&fixed).unwrap()
};

Platform Considerations

Here is the underlying web engine each platform uses, and some dependencies you might need to install.

Linux

WebKitGTK is used to provide webviews on Linux which requires GTK, so if the windowing library doesn't support GTK (as in [winit]) you'll need to call [gtk::init] before creating the webview and then call [gtk::main_iteration_do] alongside your windowing library event loop.

#[derive(Default)]
struct App {
  webview_window: Option<(Window, WebView)>,
}

impl ApplicationHandler for App {
  fn resumed(&mut self, event_loop: &ActiveEventLoop) {
    let window = event_loop.create_window(Window::default_attributes()).unwrap();
    let webview = WebViewBuilder::new()
      .with_url("https://tauri.app")
      .build(&window)
      .unwrap();

    self.webview_window = Some((window, webview));
  }

  fn window_event(&mut self, _event_loop: &ActiveEventLoop, _window_id: WindowId, event: WindowEvent) {}

  // Advance GTK event loop <!----- IMPORTANT
  fn about_to_wait(&mut self, _event_loop: &ActiveEventLoop) {
    #[cfg(target_os = "linux")]
    while gtk::events_pending() {
      gtk::main_iteration_do(false);
    }
  }
}

let event_loop = EventLoop::new().unwrap();
let mut app = App::default();
event_loop.run_app(&mut app).unwrap();

Linux Dependencies
Arch Linux / Manjaro:

sudo pacman -S webkit2gtk-4.1

Debian / Ubuntu:

sudo apt install libwebkit2gtk-4.1-dev

Fedora

sudo dnf install gtk3-devel webkit2gtk4.1-devel

Nix & NixOS

# shell.nix

let
   # Unstable Channel | Rolling Release
   pkgs = import (fetchTarball("channel:nixpkgs-unstable")) { };
   packages = with pkgs; [
     pkg-config
     webkitgtk_4_1
   ];
 in
 pkgs.mkShell {
   buildInputs = packages;
 }

nix-shell shell.nix

GUIX

;; manifest.scm

(specifications->manifest
  '("pkg-config"                ; Helper tool used when compiling
    "webkitgtk"                 ; Web content engine fot GTK+
 ))

guix shell -m manifest.scm

macOS

WebKit is native on macOS so everything should be fine.

If you are cross-compiling for macOS using osxcross and encounter a runtime panic like Class with name WKWebViewConfiguration could not be found it's possible that WebKit.framework has not been linked correctly, to fix this set the RUSTFLAGS environment variable:

RUSTFLAGS="-l framework=WebKit" cargo build --target=x86_64-apple-darwin --release

Windows

WebView2 provided by Microsoft Edge Chromium is used. So wry supports Windows 7, 8, 10 and 11.

Android

In order for wry to be able to create webviews on Android, there are a few requirements that your application needs to uphold:

  • You need to set a few environment variables that will be used to generate the necessary kotlin
files that you need to include in your Android application for wry to function properly.
  • WRY_ANDROID_PACKAGE: which is the reversed domain name of your android project and the app name in snake_case, for example, com.wry.example.wry_app
  • WRY_ANDROID_LIBRARY: for example, if your cargo project has a lib name wry_app, it will generate libwry_app.so so you set this env var to wry_app
  • WRY_ANDROID_KOTLIN_FILES_OUT_DIR: for example, path/to/app/src/main/kotlin/com/wry/example
  • Your main Android Activity needs to inherit AppCompatActivity, preferably it should use the generated WryActivity or inherit it.
  • Your Rust app needs to call wry::android_setup function to setup the necessary logic to be able to create webviews later on.
  • Your Rust app needs to call wry::android_binding! macro to setup the JNI functions that will be called by WryActivity and various other places.
It is recommended to use the tao crate as it provides maximum compatibility with wry.

#[cfg(target_os = "android")]
{
  tao::android_binding!(
      com_example,
      wry_app,
      WryActivity,
      wry::android_setup, // pass the wry::android_setup function to tao which will be invoked when the event loop is created
      _start_app
  );
  wry::android_binding!(com_example, ttt);
}

If this feels overwhelming, you can just use the preconfigured template from cargo-mobile2.

For more information, check out MOBILE.md.

Feature flags

Wry uses a set of feature flags to toggle several advanced features.

  • os-webview (default): Enables the default WebView framework on the platform. This must be enabled
for the crate to work. This feature was added in preparation of other ports like cef and servo.
  • protocol (default): Enables [WebViewBuilder::with_custom_protocol] to define custom URL scheme for handling tasks like
loading assets.
  • drag-drop (default): Enables [WebViewBuilder::with_drag_drop_handler] to control the behavior when there are files
interacting with the window.
  • devtools: Enables devtools on release builds. Devtools are always enabled in debug builds.
On macOS, enabling devtools, requires calling private APIs so you should not enable this flag in release build if your app needs to publish to App Store.
  • transparent: Transparent background on macOS requires calling private functions.
Avoid this in release build if your app needs to publish to App Store.
  • fullscreen: Fullscreen video and other media on macOS requires calling private functions.
Avoid this in release build if your app needs to publish to App Store.
  • linux-body: Enables body support of custom protocol request on Linux. Requires
WebKit2GTK v2.40 or above.
  • tracing: enables [tracing] for evaluate_script, ipc_handler, and custom_protocols.

Partners

CrabNebula

For the complete list of sponsors please visit our website and Open Collective.

License

Apache-2.0/MIT