Loanb222
Loanb222

Reputation: 851

UIActivityViewController in Swift Crashes on iPad

I am making a share function in my game and I have the code and it works fine on iPhone but when I test it on a iPad, when I tap the share button the app crashes. I am using the following code for the share button

let textToShare = "Check out this website!"

if let myWebsite = NSURL(string: "http://www.apple.com/") {
   let objectsToShare = [textToShare, myWebsite]
   let activityVC = UIActivityViewController(activityItems: objectsToShare, applicationActivities: nil)
   self.view?.window?.rootViewController?.presentViewController(activityVC, animated: true, completion: nil)
}

Upvotes: 21

Views: 10152

Answers (5)

AYUSH KUMAR
AYUSH KUMAR

Reputation: 1

In iPad SheetVC is not present. So you need to add a source View for a popover controller

@objc private func shareButtonTapped(_ sender: UIButton) {
        let image = UIImage(named: "image")
        let activityItem: [AnyObject] = [image as AnyObject]
        let activityViewController = UIActivityViewController(
            activityItems: activityItem as [AnyObject],
            applicationActivities: nil
        )
        if let popoverController = activityViewController.popoverPresentationController {
            popoverController.sourceView = sender
            popoverController.sourceRect = sender.bounds
        }
        present(activityViewController, animated: true, completion: nil)
    }

Upvotes: -1

Taltus1337
Taltus1337

Reputation: 11

iOS 16 ready-to-use example based on previous examples, without using deprecated windows

func shareAppIntent() {
    let subject = "Share with Friends"
    let extraText = "https://apps.apple.com/..."
    
    guard let mainWindowScene = UIApplication.shared.connectedScenes
            .compactMap({ $0 as? UIWindowScene })
            .first(where: { $0.activationState == .foregroundActive }),
          let mainWindow = mainWindowScene.windows.first,
          let rootViewController = mainWindow.rootViewController else {
        return
    }
    
    if let url = URL(string: extraText) {
        let activityViewController = UIActivityViewController(activityItems: [subject, url], applicationActivities: nil)
        
        // iPad needs extra context, otherwise it will crash
        if UIDevice.current.userInterfaceIdiom == .pad {
            activityViewController.popoverPresentationController?.sourceView = mainWindow
            activityViewController.popoverPresentationController?.sourceRect = CGRect(x: 0, y: 0, width: 300, height: 350)
            activityViewController.popoverPresentationController?.permittedArrowDirections = [.left]
        }
        
        rootViewController.present(activityViewController, animated: true, completion: nil)
    }
}

Upvotes: -1

Jannik Arndt
Jannik Arndt

Reputation: 555

Building on @Satachito's answer: As the sourceView you can create an (invisible) CGRect at the place the popup should point to, and set the arrow in that direction:

let activityVC = UIActivityViewController(activityItems: objectsToShare, applicationActivities: nil)

if UIDevice.current.userInterfaceIdiom == .pad {
    activityVC.popoverPresentationController?.sourceView = UIApplication.shared.windows.first
    activityVC.popoverPresentationController?.sourceRect = CGRect(x: 0, y: 0, width: 300, height: 350)
    activityVC.popoverPresentationController?.permittedArrowDirections = [.left]
}

UIApplication.shared.windows.first?.rootViewController?.present(activityVC, animated: true, completion: nil)

Upvotes: 4

hectorsvill
hectorsvill

Reputation: 881

The popoverPresentationController sourceView needs to be set to current view.

let activityVC = UIActivityViewController(activityItems: [quoteController.attributedString, view.screenShot()], applicationActivities: [])
    
present(activityVC, animated: true)
activityVC.popoverPresentationController?.sourceView = view

Upvotes: -1

Satachito
Satachito

Reputation: 5888

The UIActivityViewController's has non-null popoverPresentationController property when running on iPad. So, try below.

if let wPPC = activityVC.popoverPresentationController {
    wPPC.sourceView = some view
    //  or
    wPPC.barButtonItem = some bar button item
}
presentViewController( activityVC, animated: true, completion: nil )

Upvotes: 34

Related Questions