SwiftUI Share Sheet Crashes iPad
Asked Answered
R

3

7

I was following this tutorial to add a simple share sheet to my SwiftUI app. It works properly on iPhones but crashes on iPad with this error:

Terminating app due to uncaught exception 'NSGenericException', reason: 'UIPopoverPresentationController (<UIPopoverPresentationController: 0x107d95ee0>) should have a non-nil sourceView or barButtonItem set before the presentation occurs.'

Any way to get around this error? Not exactly sure what's happening here.

Rubi answered 13/4, 2021 at 16:21 Comment(0)
C
3

You just need to set sourceView and sourceRect on the UIActivityViewController's popoverPresentationController. Here's a more complete and correct example than I've seen so far:

// Get a scene that's showing (iPad can have many instances of the same app, some in the background)
let activeScene = UIApplication.shared.connectedScenes.first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene
        
let rootViewController = (activeScene?.windows ?? []).first(where: { $0.isKeyWindow })?.rootViewController
        
// iPad stuff (fine to leave this in for all iOS devices, it will be effectively ignored when not needed)
activityVC.popoverPresentationController?.sourceView = rootViewController?.view
activityVC.popoverPresentationController?.sourceRect = .zero
        
rootViewController?.present(activityVC, animated: true, completion: nil)
Cultigen answered 23/3, 2022 at 17:41 Comment(0)
D
1

Try this code to open Actionsheet in iPad.

if let vc = UIApplication.shared.windows.first?.rootViewController{
        let activityVC = UIActivityViewController(activityItems: [urlShare], applicationActivities: nil)
        if isIpad{
            activityVC.popoverPresentationController?.sourceView = vc.view
            activityVC.popoverPresentationController?.sourceRect = .zero
        }
        UIApplication.shared.windows.first?.rootViewController?.present(activityVC, animated: true, completion: nil)
    }
Doriandoric answered 11/3, 2022 at 12:47 Comment(1)
What is isIpad? FYI - there's no reason to only set the sourceView and sourceRect on an iPad. It's perfectly fine to set them for all devices.Histamine
U
-1

Here is a solution without any warning, also works on iPad.

Button {
    let AV = UIActivityViewController(activityItems: ["Hello World!"], applicationActivities: nil)
    let activeScene = UIApplication.shared.connectedScenes.first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene
    let rootViewController = (activeScene?.windows ?? []).first(where: { $0.isKeyWindow })?.rootViewController
    // for iPad. if condition is optional.
    if UIDevice.current.userInterfaceIdiom == .pad{
        AV.popoverPresentationController?.sourceView = rootViewController?.view
        AV.popoverPresentationController?.sourceRect = .zero
    }
    rootViewController?.present(AV, animated: true, completion: nil)
    
} label: {
    Image(systemName: "square.and.arrow.up")
     
}
Underact answered 16/1 at 15:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.