Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS 13 UIActivityViewController automatically present previous VC after image saving

I'm trying to implement “Save image to Library” function and then return back to the current view controller, but on a new iOS 13 it dismisses back to the view controller that presented the current one:

PHPhotoLibrary.requestAuthorization({(_ status: PHAuthorizationStatus) -> Void in })  let shareItems: Array = [newImg,"Hello"] as [Any]  let activityController = UIActivityViewController(activityItems: shareItems, applicationActivities: nil)  if UIDevice.current.userInterfaceIdiom == .pad {     activityController.popoverPresentationController?.sourceView = saveButton }  present(activityController, animated: true) 
like image 342
Diana Avatar asked Jul 05 '19 12:07

Diana


2 Answers

Swift version of @KDP's solution:

let fakeViewController = TransparentViewController() fakeViewController.modalPresentationStyle = .overFullScreen  activityViewController.completionWithItemsHandler = { [weak fakeViewController] _, _, _, _ in     if let presentingViewController = fakeViewController?.presentingViewController {         presentingViewController.dismiss(animated: false, completion: nil)     } else {         fakeViewController?.dismiss(animated: false, completion: nil)     } } present(fakeViewController, animated: true) { [weak fakeViewController] in     fakeViewController?.present(activityViewController, animated: true, completion: nil) } 

fakeViewController gets either dismissed by activity completion, or we need to dismiss it in completion.

like image 98
janh Avatar answered Sep 18 '22 21:09

janh


I can confirm that this bug is still present in iOS 13.3.1. The following workaround is a Swift version of franze's solution. I prefer this approach, as it doesn't make any further assumptions on the view controller hierarchy and doesn't use method swizzling.

Using this additional UIWindow breaks the Cancel button of the UIActivityViewController on iOS 12 and earlier, so I added a check for the OS version.

private let activityWindow: UIWindow = {   let window = UIWindow(frame: UIScreen.main.bounds)   window.rootViewController = UIViewController()   return window }()  func showActivityController() {   let activityViewController = UIActivityViewController(/* ... */)   activityViewController.completionWithItemsHandler = {      // ...      UIApplication.shared.delegate?.window??.makeKeyAndVisible()          }    // Use this workaround only on iOS 13   if ProcessInfo.processInfo.operatingSystemVersion.majorVersion == 13 {     activityWindow.makeKeyAndVisible()     activityWindow.rootViewController?.present(activityViewController, animated: true)   } else {     present(activityViewController, animated: true)   } } 

Update: Apparently, this solution doesn't work reliably on iPads. It looks like on iPad the UIActivityViewController is presented differently and as soon as it's visible on screen, no touch events are registered, effectively freezing the app.

like image 36
Theo Avatar answered Sep 20 '22 21:09

Theo