diff --git a/Cargo.toml b/Cargo.toml index 9912e44..0386164 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,9 +36,8 @@ jni = "0.21" ndk-context = "0.1" [target.'cfg(any(target_os = "ios", target_os = "tvos", target_os = "visionos"))'.dependencies] -block2 = "0.5.0" -objc2 = "0.5.1" -objc2-foundation = { version = "0.2.0", default-features = false, features = [ +objc2 = "0.6" +objc2-foundation = { version = "0.3", default-features = false, features = [ "std", "NSDictionary", "NSString", diff --git a/src/ios.rs b/src/ios.rs index ea926d4..7d33ea6 100644 --- a/src/ios.rs +++ b/src/ios.rs @@ -1,21 +1,29 @@ -use crate::{Browser, BrowserOptions, Error, ErrorKind, Result, TargetType}; -use block2::Block; -use objc2::rc::Id; -use objc2::runtime::Bool; -use objc2::{class, msg_send, msg_send_id}; +use std::ffi::c_void; + +use objc2::{class, msg_send, rc::Retained, Encode, Encoding, MainThreadMarker}; use objc2_foundation::{NSDictionary, NSObject, NSString, NSURL}; -fn app() -> Option> { - unsafe { msg_send_id![class!(UIApplication), sharedApplication] } +use crate::{Browser, BrowserOptions, Error, ErrorKind, Result, TargetType}; + +/// Returns `UIApplication` +#[allow(non_snake_case)] +fn sharedApplication(_mtm: MainThreadMarker) -> Retained { + unsafe { msg_send![class!(UIApplication), sharedApplication] } +} + +/// Fake `block` to not have to depend on the `block2` crate just to set this to an empty/`None` block. +#[repr(transparent)] +struct FakeBlock(*const c_void); + +// SAFETY: The type is `#[repr(transparent)]` over a pointer (same layout as `Option<&block::Block<...>>`). +unsafe impl Encode for FakeBlock { + const ENCODING: Encoding = Encoding::Block; } -fn open_url( - app: &NSObject, - url: &NSURL, - options: &NSDictionary, - handler: Option<&Block>, -) { - unsafe { msg_send![app, openURL: url, options: options, completionHandler: handler] } +#[doc(alias = "openURL_options_completionHandler")] +fn open_url(app: &NSObject, url: &NSURL, options: &NSDictionary) { + let fake_handler = FakeBlock(std::ptr::null()); + unsafe { msg_send![app, openURL: url, options: options, completionHandler: fake_handler] } } /// Deal with opening of browsers on iOS/tvOS/visionOS. @@ -34,10 +42,11 @@ pub(super) fn open_browser_internal( return Ok(()); } - let app = app().ok_or(Error::new( + let mtm = MainThreadMarker::new().ok_or(Error::new( ErrorKind::Other, - "UIApplication is null, can't open url", + "UIApplication must be retrieved on the main thread", ))?; + let app = sharedApplication(mtm); // Create ns string class from our string let url_string = NSString::from_str(url); @@ -50,6 +59,6 @@ pub(super) fn open_browser_internal( let options = NSDictionary::new(); // Open url - open_url(&app, &url_object, &options, None); + open_url(&app, &url_object, &options); Ok(()) }