From 2e089f6acb854e4d7f8eafb9b2f8242b1c9fa491 Mon Sep 17 00:00:00 2001 From: Vladimir Pankratov <8397079+Choochmeque@users.noreply.github.com> Date: Thu, 2 Oct 2025 05:00:44 -0700 Subject: [PATCH] feat(ios): support async Swift plugin methods (`completionHandler:`) in PluginManager (#14148) * Added selector with completionHandler handling * Added .changes file * fix change file --------- Co-authored-by: Lucas Nogueira --- .changes/ios-async-support.md | 5 +++++ .../mobile/ios-api/Sources/Tauri/Tauri.swift | 17 ++++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 .changes/ios-async-support.md diff --git a/.changes/ios-async-support.md b/.changes/ios-async-support.md new file mode 100644 index 000000000..cfe444e0a --- /dev/null +++ b/.changes/ios-async-support.md @@ -0,0 +1,5 @@ +--- +"tauri": minor:feat +--- + +Support async Swift plugin methods (`completionHandler:`) in PluginManager diff --git a/crates/tauri/mobile/ios-api/Sources/Tauri/Tauri.swift b/crates/tauri/mobile/ios-api/Sources/Tauri/Tauri.swift index 9a9c40e3d..cdcad76c3 100644 --- a/crates/tauri/mobile/ios-api/Sources/Tauri/Tauri.swift +++ b/crates/tauri/mobile/ios-api/Sources/Tauri/Tauri.swift @@ -59,8 +59,23 @@ public class PluginManager { func invoke(name: String, invoke: Invoke) { if let plugin = plugins[name] { ipcDispatchQueue.async { + let selectorWithCompletionHandler = Selector(("\(invoke.command):completionHandler:")) let selectorWithThrows = Selector(("\(invoke.command):error:")) - if plugin.instance.responds(to: selectorWithThrows) { + + if plugin.instance.responds(to: selectorWithCompletionHandler) { + let completion: @convention(block) (NSError?) -> Void = { error in + if let error = error { + invoke.reject("\(error)") + } + } + + let blockObj: AnyObject = unsafeBitCast(completion, to: AnyObject.self) + let imp = plugin.instance.method(for: selectorWithCompletionHandler) + + typealias Fn = @convention(c) (AnyObject, Selector, Invoke, AnyObject) -> Void + let fn = unsafeBitCast(imp, to: Fn.self) + fn(plugin.instance, selectorWithCompletionHandler, invoke, blockObj) + } else if plugin.instance.responds(to: selectorWithThrows) { var error: NSError? = nil withUnsafeMutablePointer(to: &error) { let methodIMP: IMP! = plugin.instance.method(for: selectorWithThrows)