diff --git a/packages/mobile/src/lib.rs b/packages/mobile/src/lib.rs index 7c17d65e3..7a47be4c6 100644 --- a/packages/mobile/src/lib.rs +++ b/packages/mobile/src/lib.rs @@ -5,7 +5,6 @@ pub use dioxus_desktop::*; use dioxus_lib::prelude::*; use std::any::Any; -use std::sync::Mutex; pub mod launch_bindings { @@ -33,62 +32,41 @@ pub fn launch_cfg( contexts: Vec Box + Send + Sync>>, platform_config: Vec>, ) { - #[cfg(target_os = "android")] - { - *APP_OBJECTS.lock().unwrap() = Some(BoundLaunchObjects { - root, - contexts, - platform_config, - }); - } - - #[cfg(not(target_os = "android"))] - { - dioxus_desktop::launch::launch(root, contexts, platform_config); - } + dioxus_desktop::launch::launch(root, contexts, platform_config); } -/// We need to store the root function and contexts in a static so that when the tao bindings call -/// "start_app", that the original function arguments are still around. -/// -/// If you look closely, you'll notice that we impl Send for this struct. This would normally be -/// unsound. However, we know that the thread that created these objects ("main()" - see JNI_OnLoad) -/// is finished once `start_app` is called. This is similar to how an `Rc` is technically safe -/// to move between threads if you can prove that no other thread is using the `Rc` at the same time. -/// Crates like exist that build on this idea but with runtime -/// validation that the current thread is the one that created the object. -/// -/// Since `main()` completes, the only reader of this data will be `start_app`, so it's okay to -/// impl this as Send/Sync. -/// -/// Todo(jon): the visibility of functions in this module is too public. Make sure to hide them before -/// releasing 0.7. -struct BoundLaunchObjects { - root: fn() -> Element, - contexts: Vec Box + Send + Sync>>, - platform_config: Vec>, -} - -unsafe impl Send for BoundLaunchObjects {} -unsafe impl Sync for BoundLaunchObjects {} - -static APP_OBJECTS: Mutex> = Mutex::new(None); - #[doc(hidden)] pub fn root() { - let app = APP_OBJECTS - .lock() - .expect("APP_FN_PTR lock failed") - .take() - .expect("Android to have set the app trampoline"); + fn stop_unwind T, T>(f: F) -> T { + match std::panic::catch_unwind(std::panic::AssertUnwindSafe(f)) { + Ok(t) => t, + Err(err) => { + eprintln!("attempt to unwind out of `rust` with err: {:?}", err); + std::process::abort() + } + } + } - let BoundLaunchObjects { - root, - contexts, - platform_config, - } = app; + stop_unwind(|| unsafe { + let mut main_fn_ptr = libc::dlsym(libc::RTLD_DEFAULT, b"main\0".as_ptr() as _); - dioxus_desktop::launch::launch(root, contexts, platform_config); + if main_fn_ptr.is_null() { + main_fn_ptr = libc::dlsym(libc::RTLD_DEFAULT, b"_main\0".as_ptr() as _); + } + + if main_fn_ptr.is_null() { + panic!("Failed to find main symbol"); + } + + // Set the env vars that rust code might expect, passed off to us by the android app + // Doing this before main emulates the behavior of a regular executable + if cfg!(target_os = "android") && cfg!(debug_assertions) { + load_env_file_from_session_cache(); + } + + let main_fn: extern "C" fn() = std::mem::transmute(main_fn_ptr); + main_fn(); + }); } /// Expose the `Java_dev_dioxus_main_WryActivity_create` function to the JNI layer. @@ -108,47 +86,13 @@ pub extern "C" fn start_app() { wry::android_binding!(dev_dioxus, main, wry); } -/// Call our `main` function to initialize the rust runtime and set the launch binding trampoline -#[cfg(target_os = "android")] -#[no_mangle] -#[inline(never)] -pub extern "C" fn JNI_OnLoad( - _vm: *mut libc::c_void, - _reserved: *mut libc::c_void, -) -> jni::sys::jint { - // we're going to find the `main` symbol using dlsym directly and call it - unsafe { - let mut main_fn_ptr = libc::dlsym(libc::RTLD_DEFAULT, b"main\0".as_ptr() as _); - - if main_fn_ptr.is_null() { - main_fn_ptr = libc::dlsym(libc::RTLD_DEFAULT, b"_main\0".as_ptr() as _); - } - - if main_fn_ptr.is_null() { - panic!("Failed to find main symbol"); - } - - // Set the env vars that rust code might expect, passed off to us by the android app - // Doing this before main emulates the behavior of a regular executable - if cfg!(target_os = "android") && cfg!(debug_assertions) { - load_env_file_from_session_cache(); - } - - let main_fn: extern "C" fn() = std::mem::transmute(main_fn_ptr); - main_fn(); - }; - - jni::sys::JNI_VERSION_1_6 -} - /// Load the env file from the session cache if we're in debug mode and on android /// /// This is a slightly hacky way of being able to use std::env::var code in android apps without /// going through their custom java-based system. -#[cfg(target_os = "android")] fn load_env_file_from_session_cache() { let env_file = dioxus_cli_config::android_session_cache_dir().join(".env"); - if let Some(env_file) = std::fs::read_to_string(&env_file).ok() { + if let Ok(env_file) = std::fs::read_to_string(&env_file) { for line in env_file.lines() { if let Some((key, value)) = line.trim().split_once('=') { std::env::set_var(key, value); @@ -156,24 +100,3 @@ fn load_env_file_from_session_cache() { } } } - -// #![doc = include_str!("../README.md")] -// #![doc(html_logo_url = "https://avatars.githubusercontent.com/u/79236386")] -// #![doc(html_favicon_url = "https://avatars.githubusercontent.com/u/79236386")] - -// pub use dioxus_desktop::*; -// use dioxus_lib::prelude::*; -// use std::any::Any; - -// /// Launch via the binding API -// pub fn launch(root: fn() -> Element) { -// launch_cfg(root, vec![], vec![]); -// } - -// pub fn launch_cfg( -// root: fn() -> Element, -// contexts: Vec Box + Send + Sync>>, -// platform_config: Vec>, -// ) { -// dioxus_desktop::launch::launch_cfg(root, contexts, platform_config); -// }