Register_uri_scheme_protocol - why not working on build?

Ok, enough with the chatbots. Real human help is needed now! :robot: :-1: -- :people_hugging: :+1:

I've created a disktop app using Tauri (backend) and YEW (frontend)

My app plays videos from the app's data directory (in my case on macOS ~/Library/Application Support/danceOmatic/media/)
It's then fetched using a config.toml from ~/Library/Application Support/danceOmatic/config.toml

This works seamlessly when I run dev mode (cargo tauri dev). I don't get any errors in window console ect.
But when I build the app, the app it doesn't start. Here's the code for that commit

According to claude the most likely issue is that the frontend isn't being built or included in the bundle correctly.
The changes I made to the frontend is mostly here:

//src/components/molecules/video_list.rs
use crate::components::atoms::arrow_respnd_ui::*;
use yew::prelude::*;
use serde_json::json;
use wasm_bindgen::prelude::wasm_bindgen;
use wasm_bindgen::JsValue;
use serde_wasm_bindgen::{to_value, from_value};
use web_sys::console;
use web_sys::{Blob as WebBlob, Url};


#[derive(Clone, PartialEq)]
pub struct Video {
...
}

#[derive(Clone, PartialEq)]
pub struct DemoVideo {
...
}

#[derive(Clone, PartialEq)]
pub enum VideoType {
    Regular(Video),
    Demo(DemoVideo),
}

impl VideoType {
...
}

#[wasm_bindgen]
extern "C" {
    #[wasm_bindgen(js_namespace = ["window", "__TAURI__", "core"], js_name = invoke)]
    async fn invoke(cmd: &str, args: JsValue) -> JsValue;
}

#[derive(Properties, PartialEq)]
pub struct VideosListProps {
...
}

#[function_component(VideosList)]
pub fn videos_list(props: &VideosListProps) -> Html {
    
    use_effect(|| {
        web_sys::console::log_1(&"VideosList mounted".into());
        || ()
    });

    let VideosListProps {
        videos,
        current_index,
        on_ended,
        video_class,
    } = props;

    let current_video = &videos[*current_index]; // <- get current_index to display the corresponding video. Access the inner Video with .video
    let video = current_video.get_video();
    let should_loop = current_video.should_loop();
    let onended_attr = if !should_loop {
        on_ended.clone().map(|callback| {
            Callback::from(move |_| {
                callback.emit(());
            })
        })
    } else {
        None
    };
   
    // This codeblock should Resolve path using Tauri backend
    let video_src = use_state(|| None);
    {   
        let video_src = video_src.clone();
        let video_name = current_video.get_video().url.clone(); // e.g. "static/devVideo/DEMO_LetsDuet.mp4"

        use_effect_with(video_name.clone(), move |video_name| {
            let video_src = video_src.clone();

            wasm_bindgen_futures::spawn_local({
                let video_name = video_name.clone();
                async move {
                    console::time_with_label("get_video_path");
                    let js_args = serde_wasm_bindgen::to_value(&json!({ "path": video_name })).unwrap();
                    let result = invoke("resolve_media_path", js_args).await;
                    
                     match serde_wasm_bindgen::from_value::<String>(result) {
                        Ok(url) => {
                            log::info!("🎥 Video path resolved: {}", &url);
                            video_src.set(Some(url));
                            console::time_end_with_label("get_video_path");
                        }
                        Err(err) => log::error!("❌ Failed to parse video blob: {:?}", err),
                    }
            
       
                    
                }
            });
            || ()
        });

    }

    match current_video {

        VideoType::Demo(demo) => {
        let src = video_src.as_ref().cloned().unwrap_or_default();
        log::info!("🎬 Final video_src to render: {}", src);
        
        html! {
        <div class="main_menu-container">
                <div class="video-wrapper">
                    <div class="svg-arrow-in-main">
                    <ArrowUpIcon/>
                    </div>

                <p class="title-center arcadefont">{current_video.get_displayed_id().unwrap_or_default()}</p>
                    <div class="video-placeholder">
                    <video
                        
                        src={video_src.as_ref().cloned().unwrap_or_default()}


                        autoplay=true
                        loop={should_loop}
                        onended={onended_attr}
                        class={classes!(video_class.clone(), "smallscreenvideo")}
                        preload="auto"
                    />
                    </div>
                    <div class="svg-arrow-in-main">
                    <ArrowDownIcon/>
                    </div>

                    
                </div>
                <div class="right-column">
                <div class="video-info arcadefont">
                    <h4>{format!("{}", &demo.title)}</h4>
                    <h4>{"Duration: "}{&demo.duration}{" seconds"}</h4>
                </div>
            </div>
            </div>
            }
        },
        VideoType::Regular(_) => html! {
            <video
                src={video_src.as_ref().cloned().unwrap_or_default()}
                autoplay=true
                loop={should_loop}
                onended={onended_attr}
                class={classes!(video_class.clone(), "fullscreenvideo")}
                preload="auto"
            />
        },
    }
}

The backend files that I've been working around in is //src-tauri/src/lib.rs

Mostly section:

.register_uri_scheme_protocol("media", |app, request| {
            let app_handle = app.app_handle();  

            // Get media directory
            let media_dir = app_handle
                .path()
                .app_data_dir()
                .expect("Could not get app dir")
                .join("media");

            // Parse file path from URI
            let uri = request.uri().to_string();
            let rel_path = uri.trim_start_matches("media://").trim_end_matches('/');
            let full_path = media_dir.join(rel_path);

            // Debug logging
            eprintln!("🔍 Original URI: {}", uri);
            eprintln!("🔍 Relative path: '{}'", rel_path);
            eprintln!("🔍 Full path: {:?}", full_path);

                // Try to read the file
                match std::fs::read(&full_path) {
                Ok(data) => {
                    let mime = mime_guess::from_path(&full_path).first_or_octet_stream();
                    match Response::builder()
                        .header("Content-Type", mime.as_ref())
                        .body(data) {
                        Ok(resp) => resp,
                        Err(e) => {
                            eprintln!("Failed to build response: {}", e);
                            Response::builder()
                                .status(500)
                                .body(Vec::new())
                                .unwrap()
                        }
                    }
                }
                Err(e) => {
                    eprintln!("🛑 media:// failed to load {}: {}", rel_path, e);
                    Response::builder()
                        .status(404)
                        .body(Vec::new())
                        .unwrap()
                }
            }
        })

And then //src-tauri/src/commands.rs


I have successfully build the app when I convert the path to a array of bites. But that is very slow.

That commit can be found here: blob commit

I promise to be very responsive to any help I might be given.
Thank you!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.