diff --git a/.changes/ios-custom-url-schemes.md b/.changes/ios-custom-url-schemes.md new file mode 100644 index 0000000000..7353ce4169 --- /dev/null +++ b/.changes/ios-custom-url-schemes.md @@ -0,0 +1,35 @@ +--- +"tao": patch +--- + +# iOS: added custom URL schemes handling in the AppDelegate class + +Until now, only ["associated +domains"](https://developer.apple.com/documentation/xcode/supporting-associated-domains) +were handled, using the `application_continue` function, that implements [this +Swift method from the `UIApplicationDelegate` +class](https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623072-application). + +For [custom URL +schemes](https://developer.apple.com/documentation/xcode/defining-a-custom-url-scheme-for-your-app), +I added a new `application_open_url` function that matches the signature of +[this other Swift +method](https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623112-application). + +Most of the code of the pre-existing `application_continue` has been moved +into a separate `handle_deep_link` function so the new `application_open_url` +can call it as well. + +I believe using the same `Event::Opened` event is appropriate in both +situations. Since the scheme is part of the URL, a listener can differentiate +between them if needed. + +## Tauri: + +Since we are emitting the same `Event::Opened` event, this change +works automatically with the ["Deep Linking" +plugin](https://v2.tauri.app/plugin/deep-linking/) without further +modifications. + +Custom URL schemes in mobile apps are essential, for example, +when dealing with OAuth redirect URLs. diff --git a/src/platform_impl/ios/view.rs b/src/platform_impl/ios/view.rs index 18b6025b86..bed79b8569 100644 --- a/src/platform_impl/ios/view.rs +++ b/src/platform_impl/ios/view.rs @@ -555,7 +555,40 @@ pub fn create_delegate_class() { YES } + fn handle_deep_link(url: id) { + unsafe { + let absolute_url: id = msg_send![url, absoluteString]; + let bytes = { + let bytes: *const c_char = msg_send![absolute_url, UTF8String]; + bytes as *const u8 + }; + + // 4 represents utf8 encoding + let len = msg_send![absolute_url, lengthOfBytesUsingEncoding: 4]; + let bytes = std::slice::from_raw_parts(bytes, len); + + let url = url::Url::parse(std::str::from_utf8(bytes).unwrap()).unwrap(); + + app_state::handle_nonuser_event(EventWrapper::StaticEvent(Event::Opened { urls: vec![url] })); + } + } + + // custom URL schemes + // https://developer.apple.com/documentation/xcode/defining-a-custom-url-scheme-for-your-app + extern "C" fn application_open_url( + _self: &mut Object, + _cmd: Sel, + _app: id, + url: id, + _options: id, + ) -> BOOL { + handle_deep_link(url); + + YES + } + // universal links + // https://developer.apple.com/documentation/xcode/supporting-universal-links-in-your-app extern "C" fn application_continue( _: &mut Object, _: Sel, @@ -568,19 +601,8 @@ pub fn create_delegate_class() { if webpage_url == nil { return NO; } - let absolute_url: id = msg_send![webpage_url, absoluteString]; - let bytes = { - let bytes: *const c_char = msg_send![absolute_url, UTF8String]; - bytes as *const u8 - }; - // 4 represents utf8 encoding - let len = msg_send![absolute_url, lengthOfBytesUsingEncoding: 4]; - let bytes = std::slice::from_raw_parts(bytes, len); - - let url = url::Url::parse(std::str::from_utf8(bytes).unwrap()).unwrap(); - - app_state::handle_nonuser_event(EventWrapper::StaticEvent(Event::Opened { urls: vec![url] })); + handle_deep_link(webpage_url); YES } @@ -631,6 +653,11 @@ pub fn create_delegate_class() { did_finish_launching as extern "C" fn(&mut Object, Sel, id, id) -> BOOL, ); + decl.add_method( + sel!(application:openURL:options:), + application_open_url as extern "C" fn(&mut Object, Sel, id, id, id) -> BOOL, + ); + decl.add_method( sel!(application:continueUserActivity:restorationHandler:), application_continue as extern "C" fn(&mut Object, Sel, id, id, id) -> BOOL,