Skip to content

Extend lifetime of custom protocol handler #371

@lucasfernog

Description

@lucasfernog

The macOS implementation for custom protocol handler stores the callback function pointers and drops them on the impl Drop for InnerWebView. The pointer is used by the objc code here.

I'm not sure how to check if the this.get_ivar::<*mut c_void>("function") is a invalid pointer, but we should do it because this example crashes with Segmentation fault: 11:

// Copyright 2019-2021 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

fn main() -> wry::Result<()> {
  use std::fs::{canonicalize, read};

  use wry::{
    application::{
      event::{Event, StartCause, WindowEvent},
      event_loop::{ControlFlow, EventLoop},
      window::WindowBuilder,
    },
    webview::WebViewBuilder,
  };

  let event_loop = EventLoop::new();
  let window = WindowBuilder::new()
    .with_title("Hello World")
    .build(&event_loop)
    .unwrap();

  let webview = WebViewBuilder::new(window)
    .unwrap()
    .with_custom_protocol("wry".into(), move |requested_asset_path| {
      // Remove url scheme
      let path = requested_asset_path.replace("wry://", "");
      // Read the file content from file path
      let content = read(canonicalize(&path)?)?;

      // Return asset contents and mime types based on file extentions
      // If you don't want to do this manually, there are some crates for you.
      // Such as `infer` and `mime_guess`.
      if path.ends_with(".html") {
        Ok((content, String::from("text/html")))
      } else if path.ends_with(".js") {
        Ok((content, String::from("text/javascript")))
      } else if path.ends_with(".png") {
        Ok((content, String::from("image/png")))
      } else {
        unimplemented!();
      }
    })
    // tell the webview to load the custom protocol
    .with_url("wry://examples/index.html")?
    .build()?;

  let mut w = vec![webview];

  event_loop.create_proxy().send_event(()).unwrap();

  event_loop.run(move |event, _, control_flow| {
    *control_flow = ControlFlow::Wait;

    match event {
      Event::UserEvent(_) => {
        w = vec![];
      }
      Event::NewEvents(StartCause::Init) => println!("Wry application started!"),
      Event::WindowEvent {
        event: WindowEvent::CloseRequested,
        ..
      } => *control_flow = ControlFlow::Exit,
      _ => (),
    }
  });
}

The example applies a small change to the custom_protocol example: immediately drop the webview, which means that the protocol handler is dropped while the macOS start_task callback is running.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions