From 23d43918a3bcee01e87eee6d37397a5bd32006ac Mon Sep 17 00:00:00 2001 From: Michal Drbohlav Date: Mon, 3 Aug 2026 17:03:14 +0200 Subject: [PATCH] fix(share): present share sheet from the topmost view controller on iOS On iOS, share() rejected with "Can't share while sharing is in progress" whenever any view controller was presented over the bridge view controller, not only when a share sheet was already open. Any app that presents a native modal over the webview - an in-app browser, a camera or document picker, a secondary WKWebView, a native auth session - could not share while that modal was on screen, and the error reported a share state that did not exist. Removing the guard alone is not enough: bridge.viewController cannot present while it already has a presentedViewController, so UIKit logs "Attempt to present ... which is already presenting ..." and no sheet appears. Walk the presentation chain and reject only when a UIActivityViewController is found in it, then present from the topmost view controller. Anchor the iPad popover to that controller's own view, since setCenteredPopover anchors to bridge.viewController.view, which is not in the presenter's hierarchy when presenting from a different view controller. Behaviour is unchanged when nothing is presented. This aligns iOS with the Android implementation, which tracks an isPresenting flag and already rejects only during an actual share. --- .../ios/Sources/SharePlugin/SharePlugin.swift | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/share/ios/Sources/SharePlugin/SharePlugin.swift b/share/ios/Sources/SharePlugin/SharePlugin.swift index 73aa61b2b..234c5f286 100644 --- a/share/ios/Sources/SharePlugin/SharePlugin.swift +++ b/share/ios/Sources/SharePlugin/SharePlugin.swift @@ -64,12 +64,28 @@ public class SharePlugin: CAPPlugin, CAPBridgedPlugin { } } - if self?.bridge?.viewController?.presentedViewController != nil { - call.reject("Can't share while sharing is in progress") - return + // Present from the topmost presented view controller so the share sheet appears + // above any view controller the app has presented over the webview. With nothing + // presented this resolves to the bridge view controller, i.e. unchanged behaviour. + // A share is only in progress when a share sheet is already presented. + var presenter = self?.bridge?.viewController + while let presented = presenter?.presentedViewController { + if presented is UIActivityViewController { + call.reject("Can't share while sharing is in progress") + return + } + presenter = presented + } + // `setCenteredPopover` anchors to the bridge view controller's view, which is not in + // the presenter's hierarchy when presenting from a different view controller. Anchor + // the popover to the presenting view controller's own view instead, centered and + // without an arrow, matching `setCenteredPopover` behaviour. + if let popover = actionController.popoverPresentationController, let presenterView = presenter?.view { + popover.sourceView = presenterView + popover.sourceRect = CGRect(x: presenterView.bounds.midX, y: presenterView.bounds.midY, width: 0, height: 0) + popover.permittedArrowDirections = [] } - self?.setCenteredPopover(actionController) - self?.bridge?.viewController?.present(actionController, animated: true, completion: nil) + presenter?.present(actionController, animated: true, completion: nil) } } }