SwiftUI Share Sheet Crashes iPad

1.1k views Asked by At

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.

3

There are 3 answers

1
Dhaval Bera On

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)
    }
0
Trev14 On

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)
0
Jakir Hossain On

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")
     
}