On iOS8 I\'m using a UIActivityViewController to share a UIImage to Facebook/Twitter etc. It seemed to be working fine, but today it suddenly started crashing when running t
Here is how I solved with swift:
let someText:String = "shareText"
let google:NSURL = NSURL(string:"http://google.com")!
let activityViewController = UIActivityViewController(activityItems: [someText, google], applicationActivities: nil)
if respondsToSelector("popoverPresentationController") {
self.senderView.presentViewController(activityViewController, animated: true, completion: nil)
activityViewController.popoverPresentationController?.sourceView = sender
}else{
senderView.presentViewController(activityViewController, animated: true, completion: nil)
}
If you present UIActivityViewController
for sharing in the following way, your app will work correctly but it will crash on iPad devices.
func shareSiteURL()
{
let title = "My app"
let url = URL(string: "https://myWebSite.com")
let activityController = UIActivityViewController(activityItems: [url!, title], applicationActivities: nil)
self.present(activityController, animated: true, completion: nil)
}
When you presented UIActivityViewController
on the iPad, the iPad presents the activity controller as a popover controller and hence it needs to know and use the source view. On the previous code, we did not pass the source view in case if the device is an iPad and that is why the app crashed when running on iPad.
To solve this issue, we are going to check if the controller is presented as a popover (the app is running on iPad) and if so, we will pass the source view otherwise the app will crash.
func shareSiteURL()
{
let title = "My app"
let url = URL(string: "https://myWebSite.com")
// check if the controller is presented as a popover (the app is running on iPad)
// and if so, we will pass the source view otherwise the app will crash.
if let popoverController = activityController.popoverPresentationController
{
popoverController.sourceView = viewController.view
}
let activityController = UIActivityViewController(activityItems: [url!, title], applicationActivities: nil)
self.present(activityController, animated: true, completion: nil)
}
popoverPresentationController
was new to iOS 8 and will crash on iOS 7. It'll also be nil on iPhone because it's only in a UIPopover
on iPad. Here's Christian's answer in Swift, with those facts taken into account:
let controller = UIActivityViewController(activityItems: [text, url, myImage], applicationActivities: nil)
presentViewController(controller, animated: true, completion: nil)
if #available(iOS 8.0, *) {
let presentationController = controller.popoverPresentationController
presentationController?.sourceView = view
}
let controller = UIActivityViewController(activityItems: [text, url, myImage], applicationActivities: nil)
presentViewController(controller, animated: true, completion: nil)
if controller.respondsToSelector("popoverPresentationController") {
// iOS 8+
let presentationController = controller.popoverPresentationController
presentationController?.sourceView = view
}
Looking at the docs, I needed to define a source view for the popover controller
UIActivityViewController *controller =
[[UIActivityViewController alloc]
initWithActivityItems:@[text,url,myImage]
applicationActivities:nil];
[self presentViewController:controller animated:YES completion:nil];
UIPopoverPresentationController *presentationController =
[controller popoverPresentationController];
presentationController.sourceView = self.view;
As @mmccomb told here, on iPad the activity view controller will be displayed as a popover using the new UIPopoverPresentationController. You need to specify at least the source view:
activityViewController.popoverPresentationController.sourceView = YOURDESIREDVIEW;
If you want to show the popover anchored to any point to that view, specify it with the sourceRect property of the popoverPresentationController.