From 2387798bda22b8784966e8801c1f1e83b9e66812 Mon Sep 17 00:00:00 2001 From: Tony Date: Fri, 24 Apr 2026 22:38:34 +0800 Subject: [PATCH 1/2] refactor(android): early returns and format --- src/android/binding.rs | 267 ++++++++-------- src/android/main_pipe.rs | 649 ++++++++++++++++++++------------------- src/android/mod.rs | 89 +++--- 3 files changed, 506 insertions(+), 499 deletions(-) diff --git a/src/android/binding.rs b/src/android/binding.rs index 031cd09cc..eefc9aee9 100644 --- a/src/android/binding.rs +++ b/src/android/binding.rs @@ -97,157 +97,160 @@ fn handle_request( is_document_start_script_enabled: jboolean, ) -> JniResult { let webview_id = env.get_string(&webview_id)?; - let webview_id = webview_id.to_str().ok().unwrap_or_default(); - - if let Some(handler) = REQUEST_HANDLER.lock().unwrap().get(webview_id) { - #[cfg(feature = "tracing")] - let span = - tracing::info_span!(parent: None, "wry::custom_protocol::handle", uri = tracing::field::Empty).entered(); + let webview_id = webview_id.to_str().unwrap_or_default(); - let mut request_builder = Request::builder(); + let request_handlers = REQUEST_HANDLER.lock().unwrap(); + let Some(handler) = request_handlers.get(webview_id) else { + return Ok(*JObject::null()); + }; - let uri = env - .call_method(&request, "getUrl", "()Landroid/net/Uri;", &[])? - .l()?; - let url: JString = env - .call_method(&uri, "toString", "()Ljava/lang/String;", &[])? - .l()? - .into(); - let url = env.get_string(&url)?.to_string_lossy().to_string(); + #[cfg(feature = "tracing")] + let span = + tracing::info_span!(parent: None, "wry::custom_protocol::handle", uri = tracing::field::Empty) + .entered(); + + let mut request_builder = Request::builder(); + + let uri = env + .call_method(&request, "getUrl", "()Landroid/net/Uri;", &[])? + .l()?; + let url: JString = env + .call_method(&uri, "toString", "()Ljava/lang/String;", &[])? + .l()? + .into(); + let url = env.get_string(&url)?.to_string_lossy().to_string(); + + #[cfg(feature = "tracing")] + span.record("uri", &url); + + request_builder = request_builder.uri(&url); + + let method = env + .call_method(&request, "getMethod", "()Ljava/lang/String;", &[])? + .l() + .map(JString::from)?; + request_builder = request_builder.method( + env + .get_string(&method)? + .to_string_lossy() + .to_string() + .as_str(), + ); - #[cfg(feature = "tracing")] - span.record("uri", &url); - - request_builder = request_builder.uri(&url); - - let method = env - .call_method(&request, "getMethod", "()Ljava/lang/String;", &[])? - .l() - .map(JString::from)?; - request_builder = request_builder.method( - env - .get_string(&method)? - .to_string_lossy() - .to_string() - .as_str(), - ); + let request_headers = env + .call_method(request, "getRequestHeaders", "()Ljava/util/Map;", &[])? + .l()?; + let request_headers = JMap::from_env(env, &request_headers)?; + let mut iter = request_headers.iter(env)?; + while let Some((header, value)) = iter.next(env)? { + let header = JString::from(header); + let value = JString::from(value); + let header = env.get_string(&header)?; + let value = env.get_string(&value)?; + if let (Ok(header), Ok(value)) = ( + HeaderName::from_bytes(header.to_bytes()), + HeaderValue::from_bytes(value.to_bytes()), + ) { + request_builder = request_builder.header(header, value); + } + } - let request_headers = env - .call_method(request, "getRequestHeaders", "()Ljava/util/Map;", &[])? - .l()?; - let request_headers = JMap::from_env(env, &request_headers)?; - let mut iter = request_headers.iter(env)?; - while let Some((header, value)) = iter.next(env)? { - let header = JString::from(header); - let value = JString::from(value); - let header = env.get_string(&header)?; - let value = env.get_string(&value)?; - if let (Ok(header), Ok(value)) = ( - HeaderName::from_bytes(header.to_bytes()), - HeaderValue::from_bytes(value.to_bytes()), - ) { - request_builder = request_builder.header(header, value); - } + let final_request = match request_builder.body(Vec::new()) { + Ok(req) => req, + Err(_e) => { + #[cfg(feature = "tracing")] + tracing::warn!("Failed to build response: {_e}"); + return Ok(*JObject::null()); } + }; - let final_request = match request_builder.body(Vec::new()) { - Ok(req) => req, - Err(_e) => { - #[cfg(feature = "tracing")] - tracing::warn!("Failed to build response: {_e}"); - return Ok(*JObject::null()); - } - }; + let response = { + #[cfg(feature = "tracing")] + let _span = tracing::info_span!("wry::custom_protocol::call_handler").entered(); + (handler.handler)( + webview_id, + final_request, + is_document_start_script_enabled != 0, + ) + }; + let Some(response) = response else { + return Ok(*JObject::null()); + }; + let status = response.status(); + let status_code = status.as_u16() as i32; + let status_err = if status_code < 100 { + Some("Status code can't be less than 100") + } else if status_code > 599 { + Some("statusCode can't be greater than 599.") + } else if status_code > 299 && status_code < 400 { + Some("statusCode can't be in the [300, 399] range.") + } else { + None + }; + if let Some(_err) = status_err { + #[cfg(feature = "tracing")] + tracing::warn!("{_err}"); + return Ok(*JObject::null()); + } - let response = { - #[cfg(feature = "tracing")] - let _span = tracing::info_span!("wry::custom_protocol::call_handler").entered(); - (handler.handler)( - webview_id, - final_request, - is_document_start_script_enabled != 0, - ) - }; - if let Some(response) = response { - let status = response.status(); - let status_code = status.as_u16() as i32; - let status_err = if status_code < 100 { - Some("Status code can't be less than 100") - } else if status_code > 599 { - Some("statusCode can't be greater than 599.") - } else if status_code > 299 && status_code < 400 { - Some("statusCode can't be in the [300, 399] range.") - } else { - None - }; - if let Some(_err) = status_err { - #[cfg(feature = "tracing")] - tracing::warn!("{_err}"); - return Ok(*JObject::null()); + let reason_phrase = status.canonical_reason().unwrap_or("OK"); + let (mime_type, encoding) = if let Some(content_type) = response.headers().get(CONTENT_TYPE) { + let content_type = content_type.to_str().unwrap().trim(); + let mut s = content_type.split(';'); + let mime_type = s.next().unwrap().trim(); + let mut encoding = None; + for token in s { + let token = token.trim(); + if token.starts_with("charset=") { + encoding.replace(token.split('=').nth(1).unwrap()); + break; } - - let reason_phrase = status.canonical_reason().unwrap_or("OK"); - let (mime_type, encoding) = if let Some(content_type) = response.headers().get(CONTENT_TYPE) { - let content_type = content_type.to_str().unwrap().trim(); - let mut s = content_type.split(';'); - let mime_type = s.next().unwrap().trim(); - let mut encoding = None; - for token in s { - let token = token.trim(); - if token.starts_with("charset=") { - encoding.replace(token.split('=').nth(1).unwrap()); - break; - } - } - ( - env.new_string(mime_type)?, - if let Some(encoding) = encoding { - env.new_string(encoding)? - } else { - JString::default() - }, - ) + } + ( + env.new_string(mime_type)?, + if let Some(encoding) = encoding { + env.new_string(encoding)? } else { - (JString::default(), JString::default()) - }; + JString::default() + }, + ) + } else { + (JString::default(), JString::default()) + }; - let headers = response.headers(); - let obj = env.new_object("java/util/HashMap", "()V", &[])?; - let response_headers = { - let headers_map = JMap::from_env(env, &obj)?; - for (name, value) in headers.iter() { - // WebResourceResponse will automatically generate Content-Type and - // Content-Length headers so we should skip them to avoid duplication. - if name == CONTENT_TYPE || name == CONTENT_LENGTH { - continue; - } - let key = env.new_string(name)?; - let value = env.new_string(value.to_str().unwrap_or_default())?; - headers_map.put(env, &key, &value)?; - } - headers_map - }; + let headers = response.headers(); + let obj = env.new_object("java/util/HashMap", "()V", &[])?; + let response_headers = { + let headers_map = JMap::from_env(env, &obj)?; + for (name, value) in headers.iter() { + // WebResourceResponse will automatically generate Content-Type and + // Content-Length headers so we should skip them to avoid duplication. + if name == CONTENT_TYPE || name == CONTENT_LENGTH { + continue; + } + let key = env.new_string(name)?; + let value = env.new_string(value.to_str().unwrap_or_default())?; + headers_map.put(env, &key, &value)?; + } + headers_map + }; - let bytes = response.body(); + let bytes = response.body(); - let byte_array_input_stream = env.find_class("java/io/ByteArrayInputStream")?; - let byte_array = env.byte_array_from_slice(bytes)?; - let stream = env.new_object(byte_array_input_stream, "([B)V", &[(&byte_array).into()])?; + let byte_array_input_stream = env.find_class("java/io/ByteArrayInputStream")?; + let byte_array = env.byte_array_from_slice(bytes)?; + let stream = env.new_object(byte_array_input_stream, "([B)V", &[(&byte_array).into()])?; - let reason_phrase = env.new_string(reason_phrase)?; + let reason_phrase = env.new_string(reason_phrase)?; - let web_resource_response_class = env.find_class("android/webkit/WebResourceResponse")?; - let web_resource_response = env.new_object( + let web_resource_response_class = env.find_class("android/webkit/WebResourceResponse")?; + let web_resource_response = env.new_object( web_resource_response_class, "(Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/util/Map;Ljava/io/InputStream;)V", &[(&mime_type).into(), (&encoding).into(), status_code.into(), (&reason_phrase).into(), (&response_headers).into(), (&stream).into()], )?; - return Ok(*web_resource_response); - } - } - - Ok(*JObject::null()) + Ok(*web_resource_response) } #[allow(non_snake_case)] diff --git a/src/android/main_pipe.rs b/src/android/main_pipe.rs index 52308fd86..361288eeb 100644 --- a/src/android/main_pipe.rs +++ b/src/android/main_pipe.rs @@ -85,7 +85,7 @@ pub fn register_activity_proxy( proxy.java_vm = vm.get_java_vm_pointer() as *mut _; } else { let proxy = ActivityProxy::new(vm, activity, window_manager, webchrome_client); - activity_proxy.insert(id, proxy.clone()); + activity_proxy.insert(id, proxy); } } @@ -143,358 +143,361 @@ impl<'a> MainPipe<'a> { } pub fn recv(&mut self) -> JniResult<()> { - if let Ok((activity_id, message)) = CHANNEL.1.recv() { - match message { - WebViewMessage::CreateWebView(attrs) => { - let Some((activity, web_chrome_client)) = - activity_proxy(activity_id).map(|p| (p.activity.clone(), p.webchrome_client.clone())) - else { - #[cfg(debug_assertions)] - eprintln!("no activity found for activity id: {}", activity_id); - return Ok(()); - }; - let CreateWebViewAttributes { - url, - html, - #[cfg(any(debug_assertions, feature = "devtools"))] - devtools, - transparent, - background_color, - headers, - on_webview_created, - autoplay, - user_agent, - initialization_scripts, - id, - javascript_disabled, - .. - } = attrs; - - let string_class = self.env.find_class("java/lang/String")?; - let initialization_scripts_array = self.env.new_object_array( - initialization_scripts.len() as i32, - string_class, - self.env.new_string("")?, - )?; - for (i, init_script) in initialization_scripts.into_iter().enumerate() { - self.env.set_object_array_element( - &initialization_scripts_array, - i as i32, - self.env.new_string(init_script.script)?, - )?; - } - let id = self.env.new_string(id)?; - // Create webview - let rust_webview_class = find_class( - &mut self.env, - &activity, - format!("{}/RustWebView", PACKAGE.get().unwrap()), + // SAFETY: The `CHANNEL` is `static` that the sender never drops + let (activity_id, message) = CHANNEL.1.recv().unwrap(); + match message { + WebViewMessage::CreateWebView(attrs) => { + let Some(ActivityProxy { + activity, + webchrome_client, + .. + }) = activity_proxy(activity_id) + else { + #[cfg(debug_assertions)] + eprintln!("no activity found for activity id: {}", activity_id); + return Ok(()); + }; + let CreateWebViewAttributes { + url, + html, + #[cfg(any(debug_assertions, feature = "devtools"))] + devtools, + transparent, + background_color, + headers, + on_webview_created, + autoplay, + user_agent, + initialization_scripts, + id, + javascript_disabled, + .. + } = attrs; + + let string_class = self.env.find_class("java/lang/String")?; + let initialization_scripts_array = self.env.new_object_array( + initialization_scripts.len() as i32, + string_class, + self.env.new_string("")?, + )?; + for (i, init_script) in initialization_scripts.into_iter().enumerate() { + self.env.set_object_array_element( + &initialization_scripts_array, + i as i32, + self.env.new_string(init_script.script)?, )?; - let webview = self.env.new_object( - &rust_webview_class, - "(Landroid/content/Context;[Ljava/lang/String;Ljava/lang/String;)V", - &[ - (&activity).into(), - (&initialization_scripts_array).into(), - (&id).into(), - ], + } + let id = self.env.new_string(id)?; + // Create webview + let rust_webview_class = find_class( + &mut self.env, + &activity, + format!("{}/RustWebView", PACKAGE.get().unwrap()), + )?; + let webview = self.env.new_object( + &rust_webview_class, + "(Landroid/content/Context;[Ljava/lang/String;Ljava/lang/String;)V", + &[ + (&activity).into(), + (&initialization_scripts_array).into(), + (&id).into(), + ], + )?; + // get settings + let web_settings = self + .env + .call_method( + &webview, + "getSettings", + "()Landroid/webkit/WebSettings;", + &[], + )? + .l()?; + // set media autoplay + self.env.call_method( + &web_settings, + "setMediaPlaybackRequiresUserGesture", + "(Z)V", + &[(!autoplay).into()], + )?; + // set user-agent + if let Some(user_agent) = user_agent { + let user_agent = self.env.new_string(user_agent)?; + self.env.call_method( + &web_settings, + "setUserAgentString", + "(Ljava/lang/String;)V", + &[(&user_agent).into()], )?; - // get settings - let web_settings = self - .env - .call_method( - &webview, - "getSettings", - "()Landroid/webkit/WebSettings;", - &[], - )? - .l()?; - // set media autoplay + } + + // disable javascript + if javascript_disabled { self.env.call_method( &web_settings, - "setMediaPlaybackRequiresUserGesture", + "setJavaScriptEnabled", "(Z)V", - &[(!autoplay).into()], + &[false.into()], )?; - // set user-agent - if let Some(user_agent) = user_agent { - let user_agent = self.env.new_string(user_agent)?; - self.env.call_method( - &web_settings, - "setUserAgentString", - "(Ljava/lang/String;)V", - &[(&user_agent).into()], - )?; - } + } - // disable javascript - if javascript_disabled { - self.env.call_method( - &web_settings, - "setJavaScriptEnabled", - "(Z)V", - &[false.into()], - )?; + let webview_class_name = format!("{}/RustWebView", PACKAGE.get().unwrap()); + self.env.call_method( + &activity, + "setWebView", + format!("(L{webview_class_name};)V"), + &[(&webview).into()], + )?; + // Navigation + if let Some(u) = url { + if let Ok(url) = self.env.new_string(u) { + load_url(&mut self.env, &webview, &url, headers, true)?; } - - let webview_class_name = format!("{}/RustWebView", PACKAGE.get().unwrap()); - self.env.call_method( - &activity, - "setWebView", - format!("(L{webview_class_name};)V"), - &[(&webview).into()], - )?; - // Navigation - if let Some(u) = url { - if let Ok(url) = self.env.new_string(u) { - load_url(&mut self.env, &webview, &url, headers, true)?; - } - } else if let Some(h) = html { - if let Ok(html) = self.env.new_string(h) { - load_html(&mut self.env, &webview, &html)?; - } + } else if let Some(h) = html { + if let Ok(html) = self.env.new_string(h) { + load_html(&mut self.env, &webview, &html)?; } - // Enable devtools - #[cfg(any(debug_assertions, feature = "devtools"))] - self.env.call_static_method( - &rust_webview_class, - "setWebContentsDebuggingEnabled", - "(Z)V", - &[devtools.into()], - )?; - if transparent { - set_background_color(&mut self.env, &webview, (0, 0, 0, 0))?; - } else if let Some(color) = background_color { - set_background_color(&mut self.env, &webview, color)?; + } + // Enable devtools + #[cfg(any(debug_assertions, feature = "devtools"))] + self.env.call_static_method( + &rust_webview_class, + "setWebContentsDebuggingEnabled", + "(Z)V", + &[devtools.into()], + )?; + if transparent { + set_background_color(&mut self.env, &webview, (0, 0, 0, 0))?; + } else if let Some(color) = background_color { + set_background_color(&mut self.env, &webview, color)?; + } + // Create and set webview client + let client_class_name = format!("{}/RustWebViewClient", PACKAGE.get().unwrap()); + let rust_webview_client_class = + find_class(&mut self.env, &activity, client_class_name.clone())?; + let webview_client = self.env.new_object( + &rust_webview_client_class, + format!("(L{webview_class_name};Landroid/content/Context;)V"), + &[(&webview).into(), (&activity).into()], + )?; + self.env.call_method( + &webview, + "setWebViewClient", + "(Landroid/webkit/WebViewClient;)V", + &[(&webview_client).into()], + )?; + // set webchrome client + self.env.call_method( + &webview, + "setWebChromeClient", + "(Landroid/webkit/WebChromeClient;)V", + &[webchrome_client.as_obj().into()], + )?; + + // Add javascript interface (IPC) + let ipc_class = find_class( + &mut self.env, + &activity, + format!("{}/Ipc", PACKAGE.get().unwrap()), + )?; + let ipc = self.env.new_object( + ipc_class, + format!("(L{webview_class_name};L{client_class_name};)V"), + &[(&webview).into(), (&webview_client).into()], + )?; + let ipc_str = self.env.new_string("ipc")?; + self.env.call_method( + &webview, + "addJavascriptInterface", + "(Ljava/lang/Object;Ljava/lang/String;)V", + &[(&ipc).into(), (&ipc_str).into()], + )?; + + // Set content view + self.env.call_method( + &activity, + "setContentView", + "(Landroid/view/View;)V", + &[(&webview).into()], + )?; + + if let Some(on_webview_created) = on_webview_created { + if let Err(_e) = on_webview_created(super::Context { + env: &mut self.env, + activity: &activity, + webview: &webview, + }) { + #[cfg(feature = "tracing")] + tracing::warn!("failed to run webview created hook: {_e}"); } - // Create and set webview client - let client_class_name = format!("{}/RustWebViewClient", PACKAGE.get().unwrap()); - let rust_webview_client_class = - find_class(&mut self.env, &activity, client_class_name.clone())?; - let webview_client = self.env.new_object( - &rust_webview_client_class, - format!("(L{webview_class_name};Landroid/content/Context;)V"), - &[(&webview).into(), (&activity).into()], - )?; - self.env.call_method( - &webview, - "setWebViewClient", - "(Landroid/webkit/WebViewClient;)V", - &[(&webview_client).into()], - )?; - // set webchrome client - self.env.call_method( - &webview, - "setWebChromeClient", - "(Landroid/webkit/WebChromeClient;)V", - &[web_chrome_client.as_obj().into()], - )?; - - // Add javascript interface (IPC) - let ipc_class = find_class( - &mut self.env, - &activity, - format!("{}/Ipc", PACKAGE.get().unwrap()), - )?; - let ipc = self.env.new_object( - ipc_class, - format!("(L{webview_class_name};L{client_class_name};)V"), - &[(&webview).into(), (&webview_client).into()], - )?; - let ipc_str = self.env.new_string("ipc")?; - self.env.call_method( - &webview, - "addJavascriptInterface", - "(Ljava/lang/Object;Ljava/lang/String;)V", - &[(&ipc).into(), (&ipc_str).into()], - )?; + } - // Set content view - self.env.call_method( - &activity, - "setContentView", - "(Landroid/view/View;)V", - &[(&webview).into()], - )?; + let webview = self.env.new_global_ref(webview)?; - if let Some(on_webview_created) = on_webview_created { - if let Err(_e) = on_webview_created(super::Context { - env: &mut self.env, - activity: &activity, - webview: &webview, - }) { - #[cfg(feature = "tracing")] - tracing::warn!("failed to run webview created hook: {_e}"); - } - } + ACTIVITY_PROXY + .lock() + .unwrap() + .get_mut(&activity_id) + .unwrap() + .webview + .replace(webview); + } + WebViewMessage::Eval(script, callback) => { + if let Some(webview) = get_webview(activity_id) { + let id = EVAL_ID_GENERATOR.next() as i32; - let webview = self.env.new_global_ref(webview)?; + #[cfg(feature = "tracing")] + let span = std::sync::Mutex::new(Some(SendEnteredSpan( + tracing::debug_span!("wry::eval").entered(), + ))); - ACTIVITY_PROXY + EVAL_CALLBACKS + .get_or_init(Default::default) .lock() .unwrap() - .get_mut(&activity_id) - .unwrap() - .webview - .replace(webview); - } - WebViewMessage::Eval(script, callback) => { - if let Some(webview) = get_webview(activity_id) { - let id = EVAL_ID_GENERATOR.next() as i32; - - #[cfg(feature = "tracing")] - let span = std::sync::Mutex::new(Some(SendEnteredSpan( - tracing::debug_span!("wry::eval").entered(), - ))); - - EVAL_CALLBACKS - .get_or_init(Default::default) - .lock() - .unwrap() - .insert( - id, - Box::new(move |result| { - #[cfg(feature = "tracing")] - span.lock().unwrap().take(); - - if let Some(callback) = &callback { - callback(result); - } - }), - ); - - let s = self.env.new_string(script)?; - self.env.call_method( - webview.as_obj(), - "evalScript", - "(ILjava/lang/String;)V", - &[id.into(), (&s).into()], - )?; - } + .insert( + id, + Box::new(move |result| { + #[cfg(feature = "tracing")] + span.lock().unwrap().take(); + + if let Some(callback) = &callback { + callback(result); + } + }), + ); + + let s = self.env.new_string(script)?; + self.env.call_method( + webview.as_obj(), + "evalScript", + "(ILjava/lang/String;)V", + &[id.into(), (&s).into()], + )?; } - WebViewMessage::SetBackgroundColor(background_color) => { - if let Some(webview) = get_webview(activity_id) { - set_background_color(&mut self.env, webview.as_obj(), background_color)?; - } + } + WebViewMessage::SetBackgroundColor(background_color) => { + if let Some(webview) = get_webview(activity_id) { + set_background_color(&mut self.env, webview.as_obj(), background_color)?; } - WebViewMessage::GetWebViewVersion(tx) => { - if let Some(activity) = activity_proxy(activity_id).map(|p| p.activity.clone()) { - match self - .env - .call_method(activity, "getVersion", "()Ljava/lang/String;", &[]) - .and_then(|v| v.l()) - .and_then(|s| { - let s = JString::from(s); - self - .env - .get_string(&s) - .map(|v| v.to_string_lossy().to_string()) - }) { - Ok(version) => { - tx.send(Ok(version)).unwrap(); - } - Err(e) => tx.send(Err(e.into())).unwrap(), + } + WebViewMessage::GetWebViewVersion(tx) => { + if let Some(activity) = activity_proxy(activity_id).map(|p| p.activity) { + match self + .env + .call_method(activity, "getVersion", "()Ljava/lang/String;", &[]) + .and_then(|v| v.l()) + .and_then(|s| { + let s = JString::from(s); + self + .env + .get_string(&s) + .map(|v| v.to_string_lossy().to_string()) + }) { + Ok(version) => { + tx.send(Ok(version)).unwrap(); } - } else { - tx.send(Err(Error::ActivityNotFound)).unwrap(); + Err(e) => tx.send(Err(e.into())).unwrap(), } + } else { + tx.send(Err(Error::ActivityNotFound)).unwrap(); } - WebViewMessage::GetUrl(tx) => { - if let Some(webview) = get_webview(activity_id) { - let url = self - .env - .call_method(webview.as_obj(), "getUrl", "()Ljava/lang/String;", &[]) - .and_then(|v| v.l()) - .and_then(|s| { - let s = JString::from(s); - self - .env - .get_string(&s) - .map(|v| v.to_string_lossy().to_string()) - }) - .unwrap_or_default(); - - tx.send(url).unwrap() - } + } + WebViewMessage::GetUrl(tx) => { + if let Some(webview) = get_webview(activity_id) { + let url = self + .env + .call_method(webview.as_obj(), "getUrl", "()Ljava/lang/String;", &[]) + .and_then(|v| v.l()) + .and_then(|s| { + let s = JString::from(s); + self + .env + .get_string(&s) + .map(|v| v.to_string_lossy().to_string()) + }) + .unwrap_or_default(); + + tx.send(url).unwrap() } - WebViewMessage::Jni(f) => { - match activity_proxy(activity_id).map(|p| (p.activity.clone(), p.webview.clone())) { - Some((activity, Some(webview))) => { - f(&mut self.env, &activity, webview.as_obj()); - } - Some((activity, None)) => { - f(&mut self.env, &activity, &JObject::null()); - } - _ => { - f(&mut self.env, &JObject::null(), &JObject::null()); - } + } + WebViewMessage::Jni(f) => { + match activity_proxy(activity_id).map(|p| (p.activity.clone(), p.webview)) { + Some((activity, Some(webview))) => { + f(&mut self.env, &activity, webview.as_obj()); } - } - WebViewMessage::LoadUrl(url, headers) => { - if let Some(webview) = get_webview(activity_id) { - let url = self.env.new_string(url)?; - load_url(&mut self.env, webview.as_obj(), &url, headers, false)?; + Some((activity, None)) => { + f(&mut self.env, &activity, &JObject::null()); } - } - WebViewMessage::ClearAllBrowsingData => { - if let Some(webview) = get_webview(activity_id) { - self - .env - .call_method(webview, "clearAllBrowsingData", "()V", &[])?; + _ => { + f(&mut self.env, &JObject::null(), &JObject::null()); } } - WebViewMessage::LoadHtml(html) => { - if let Some(webview) = get_webview(activity_id) { - let html = self.env.new_string(html)?; - load_html(&mut self.env, webview.as_obj(), &html)?; - } + } + WebViewMessage::LoadUrl(url, headers) => { + if let Some(webview) = get_webview(activity_id) { + let url = self.env.new_string(url)?; + load_url(&mut self.env, webview.as_obj(), &url, headers, false)?; } - WebViewMessage::Reload => { - if let Some(webview) = get_webview(activity_id) { - reload(&mut self.env, webview.as_obj())?; - } + } + WebViewMessage::ClearAllBrowsingData => { + if let Some(webview) = get_webview(activity_id) { + self + .env + .call_method(webview, "clearAllBrowsingData", "()V", &[])?; } - WebViewMessage::GetCookies(tx, url) => { - if let Some(webview) = get_webview(activity_id) { - let url = self.env.new_string(url)?; - let cookies = self - .env - .call_method( - webview, - "getCookies", - "(Ljava/lang/String;)Ljava/lang/String;", - &[(&url).into()], - ) - .and_then(|v| v.l()) - .and_then(|s| { - let s = JString::from(s); - self - .env - .get_string(&s) - .map(|v| v.to_string_lossy().to_string()) - }) - .unwrap_or_default(); - - tx.send( - cookies - .split("; ") - .flat_map(|c| cookie::Cookie::parse(c.to_string())) - .collect(), + } + WebViewMessage::LoadHtml(html) => { + if let Some(webview) = get_webview(activity_id) { + let html = self.env.new_string(html)?; + load_html(&mut self.env, webview.as_obj(), &html)?; + } + } + WebViewMessage::Reload => { + if let Some(webview) = get_webview(activity_id) { + reload(&mut self.env, webview.as_obj())?; + } + } + WebViewMessage::GetCookies(tx, url) => { + if let Some(webview) = get_webview(activity_id) { + let url = self.env.new_string(url)?; + let cookies = self + .env + .call_method( + webview, + "getCookies", + "(Ljava/lang/String;)Ljava/lang/String;", + &[(&url).into()], ) - .unwrap(); - } + .and_then(|v| v.l()) + .and_then(|s| { + let s = JString::from(s); + self + .env + .get_string(&s) + .map(|v| v.to_string_lossy().to_string()) + }) + .unwrap_or_default(); + + tx.send( + cookies + .split("; ") + .flat_map(|c| cookie::Cookie::parse(c.to_string())) + .collect(), + ) + .unwrap(); } - WebViewMessage::OnDestroy { - activity_id, - webview_id, - is_changing_configurations, - } => { - // keep our webview references (callbacks etc) alive if the activity is going to be recreated due to configuration changes - // e.g. rotation, multi-window mode change, etc - if !is_changing_configurations { - super::destroy_webview(activity_id, &webview_id); - remove_activity_proxy(activity_id); - } + } + WebViewMessage::OnDestroy { + activity_id, + webview_id, + is_changing_configurations, + } => { + // keep our webview references (callbacks etc) alive if the activity is going to be recreated due to configuration changes + // e.g. rotation, multi-window mode change, etc + if !is_changing_configurations { + super::destroy_webview(activity_id, &webview_id); + remove_activity_proxy(activity_id); } } } diff --git a/src/android/mod.rs b/src/android/mod.rs index 8f44c7040..ccbd863bb 100644 --- a/src/android/mod.rs +++ b/src/android/mod.rs @@ -242,50 +242,51 @@ impl InnerWebView { } let initialization_scripts_ = initialization_scripts.clone(); - REQUEST_HANDLER - .lock() - .unwrap() - .insert( - id.clone(), - UnsafeRequestHandler::new(Box::new( - move |webview_id: &str, mut request, is_document_start_script_enabled| { - let uri = request.uri().to_string(); - if let Some((custom_protocol, custom_protocol_handler)) = - custom_protocols.iter().find(|(protocol, _)| { - custom_protocol_workaround::is_work_around_uri(&uri, http_or_https, protocol) - }) - { - let uri_res = custom_protocol_workaround::revert_uri_work_around( - &uri, - http_or_https, - custom_protocol, - ) - .parse(); - - if let Ok(uri) = uri_res { - *request.uri_mut() = uri; - } - - let (tx, rx) = channel(); - let initialization_scripts = initialization_scripts_.clone(); - let responder: Box>)> = - Box::new(move |mut response| { - if !is_document_start_script_enabled { - #[cfg(feature = "tracing")] - tracing::info!("`addDocumentStartJavaScript` is not supported; injecting initialization scripts via custom protocol handler"); - response = inject_scripts_into_html(response, &initialization_scripts); - } - let _ = tx.send(response); - }); - - (custom_protocol_handler)(webview_id, request, RequestAsyncResponder { responder }); - // 3x the timeout while we monitor https://github.com/tauri-apps/wry/issues/1551 - // TODO: Remove timeout - return rx.recv_timeout(MAIN_PIPE_TIMEOUT * 3).inspect_err(|e| {eprintln!("custom protocol timed out: {e}");}).ok(); - } - None - }, - ))); + REQUEST_HANDLER.lock().unwrap().insert( + id.clone(), + UnsafeRequestHandler::new(Box::new( + move |webview_id, mut request, is_document_start_script_enabled| { + let uri = request.uri().to_string(); + let (custom_protocol, custom_protocol_handler) = + custom_protocols.iter().find(|(protocol, _)| { + custom_protocol_workaround::is_work_around_uri(&uri, http_or_https, protocol) + })?; + + let uri_res = custom_protocol_workaround::revert_uri_work_around( + &uri, + http_or_https, + custom_protocol, + ) + .parse(); + + if let Ok(uri) = uri_res { + *request.uri_mut() = uri; + } + + let (tx, rx) = channel(); + let initialization_scripts = initialization_scripts_.clone(); + let responder: Box>)> = Box::new( + move |mut response| { + if !is_document_start_script_enabled { + #[cfg(feature = "tracing")] + tracing::info!("`addDocumentStartJavaScript` is not supported; injecting initialization scripts via custom protocol handler"); + response = inject_scripts_into_html(response, &initialization_scripts); + } + let _ = tx.send(response); + }, + ); + + (custom_protocol_handler)(webview_id, request, RequestAsyncResponder { responder }); + // 3x the timeout while we monitor https://github.com/tauri-apps/wry/issues/1551 + // TODO: Remove timeout + rx.recv_timeout(MAIN_PIPE_TIMEOUT * 3) + .inspect_err(|e| { + eprintln!("custom protocol timed out: {e}"); + }) + .ok() + }, + )), + ); if let Some(i) = ipc_handler { IPC From 1096c5ecdad52cc6a50c0a08380f68a37d7c5ea6 Mon Sep 17 00:00:00 2001 From: Tony Date: Fri, 24 Apr 2026 23:39:53 +0800 Subject: [PATCH 2/2] Remove extra `.ok` --- src/android/binding.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/android/binding.rs b/src/android/binding.rs index eefc9aee9..5e870c693 100644 --- a/src/android/binding.rs +++ b/src/android/binding.rs @@ -341,7 +341,7 @@ pub unsafe fn shouldOverride( let Ok(webview_id) = env.get_string(&webview_id) else { return false.into(); }; - let webview_id = webview_id.to_str().ok().unwrap_or_default(); + let webview_id = webview_id.to_str().unwrap_or_default(); URL_LOADING_OVERRIDE .lock() @@ -429,7 +429,7 @@ pub unsafe fn withAssetLoader(mut env: JNIEnv, _: JClass, webview_id: JString) - let Ok(webview_id) = env.get_string(&webview_id) else { return false.into(); }; - let webview_id = webview_id.to_str().ok().unwrap_or_default(); + let webview_id = webview_id.to_str().unwrap_or_default(); (*WITH_ASSET_LOADER .lock() .unwrap() @@ -443,7 +443,7 @@ pub unsafe fn assetLoaderDomain(mut env: JNIEnv, _: JClass, webview_id: JString) let Ok(webview_id) = env.get_string(&webview_id) else { return env.new_string("wry.assets").unwrap().as_raw(); }; - let webview_id = webview_id.to_str().ok().unwrap_or_default(); + let webview_id = webview_id.to_str().unwrap_or_default(); if let Some(domain) = ASSET_LOADER_DOMAIN.lock().unwrap().get(webview_id) { env.new_string(domain).unwrap().as_raw() } else {