UIActivityViewController animates in a weird way when presented - ios

I am using the following code to present a UIActivityViewController:
func share(content: Any, from viewController: UIViewController) {
let activityViewController = UIActivityViewController(
activityItems: ["TEST"],
applicationActivities: []
)
DispatchQueue.main.async {
viewController.present(activityViewController, animated: true)
}
}

Try to put all in this extension:
extension UIViewController {
func share2(vc: UIViewController, content: Any) {
let text = "TEST"
let activityViewController: UIActivityViewController = UIActivityViewController(activityItems: [text], applicationActivities: nil)
DispatchQueue.main.async {
self.present(activityViewController, animated: true)
}
}
}
now call the extension func wherever you want like this:
#objc func share() {
share2(vc: self, content: yourContent)
}

I have been using EasyAnimation which advices for enabling it in AppDelegate. That was the actual issue.

Related

Sharing text and Url to Facebook Messenger with UIActivityViewController but failing

I want to share both text and url to Facebook Messenger using UIActivityViewController.
But when i success send and open my Messenger, i only get url.
Is it possible send text and url to Facebook Messenger using UIActivityViewController at the same time?
Here is my code
#IBAction func sharedLink(_ sender: Any) {
let url = NSURL(string: "https://www.google.com.tw")!
let text = "test" as AnyObject
let shareObject: [AnyObject] = [text, url as AnyObject]
let vc = UIActivityViewController(activityItems: shareObject, applicationActivities: [])
vc.completionWithItemsHandler = { (type,completed,items,error) in
if completed { vc.dismiss(animated: true, completion: nil) }
}
present(vc, animated: true, completion: nil)
}
Here is my screenshot
In my case,
#IBAction func sharedLink(_ sender: Any) {
let urlString = "https://www.google.com.tw"
let url = NSURL(string: urlString)!
let text = "test" as AnyObject
let shareObject: [AnyObject] = ["\(text), \(urlString)"]
let vc = UIActivityViewController(activityItems: shareObject, applicationActivities: [])
vc.completionWithItemsHandler = { (type,completed,items,error) in
if completed { vc.dismiss(animated: true, completion: nil) }
}
present(vc, animated: true, completion: nil)
}

UIActivityViewController dismissing current view controller after sharing file

UIActivityViewController dismisses the presenting view controller after sharing files.
this is happening in iOS 13+ only. Is there any permanent solution for this?
Others apps seem to have this issue too after updating to iOS 13.
class VC : UIViewController {
#IBAction func moveFiles(_ sender: UIButton) {
let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
alertController.addAction(UIAlertAction(title: "Move", style: .default, handler: { action in
let activityController = UIActivityViewController(activityItems: urls, applicationActivities: nil)
if (UIDevice.current.userInterfaceIdiom == UIUserInterfaceIdiom.pad) {
activityController.popoverPresentationController?.sourceRect = sender.frame
activityController.popoverPresentationController?.sourceView = sender.superview
}
self.present(activityController, animated: true, completion: nil)
}))
}
}
Here is the work around for your issue.
let tempController = TransparentViewController()
tempController.modalPresentationStyle = .overFullScreen
activityViewController.completionWithItemsHandler = { [weak tempController] _, _, _, _ in
if let presentingViewController = tempController?.presentingViewController {
presentingViewController.dismiss(animated: false, completion: nil)
} else {
tempController?.dismiss(animated: false, completion: nil)
}
}
present(tempController, animated: true) { [weak tempController] in
tempController?.present(activityViewController, animated: true, completion: nil)
}
Found similar question with solution which helps me. For iOS 13 show UIActivityViewController in another UIWindow
Stackoverflow answer
Seems it's fixed in iOS 14.4
For older iOS versions I found easier workaround. Override dismiss(animated:completion:) with empty implementation so it won't be dismissing itself automatically.
However, you can still dismiss this VC using super.dismiss(animated:completion).
E.g
override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
// do nothing to workaround bug - automatically dimisses this VC after saveToCameraRoll activity was performed
// call super.dismiss(animated:completion:) in order to really dismiss this VC
// seems fixed in iOS 14.4
}
...
#objc private func didTapCloseButton(_ sender: UIButton) {
super.dismiss(animated: true) // calling parent class implementation
}
I have same issue right now on iOS target 14.1.
I made my solution based on answers I found.
final class ShareViewController: UIViewController {
private let activityItems: [Any]
private let applicationActivities: [UIActivity]?
// Same looking initializer as UIActivityViewController has
init(activityItems: [Any], applicationActivities: [UIActivity]? = nil) {
self.activityItems = activityItems
self.applicationActivities = applicationActivities
super.init(nibName: nil, bundle: nil)
// Make transparent and covering entire screen
view.backgroundColor = .clear
modalPresentationStyle = .overCurrentContext
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Present UIActivityViewController here
presentShareSheet()
}
fileprivate func presentShareSheet() {
let shareSheet = UIActivityViewController(activityItems: activityItems,
applicationActivities: applicationActivities)
shareSheet.completionWithItemsHandler = { [weak self] _, _, _, _ in
// This is necessary to dismiss parent VC
self?.dismiss(animated: false)
}
self.present(shareSheet, animated: true)
}
}
And use it like UIActivityViewController but presenting it without animations
#objc private func shareImage() {
guard let image = imageView.image else { return }
let shareVC = ShareViewController(activityItems: [image])
present(shareVC, animated: false)
}

share PDF file with UIActivityViewController

I am trying to share a PDF file using UIActivityViewController but when I press the button I do not have options to share the file
How can I show these options ?
![](https://i.stack.imgur.com/ywDQw.jpg
import UIKit
import PDFKit
import MessageUI
import UIKit.UIGestureRecognizerSubclass
class BookViewController: UIViewController, UIPopoverPresentationControllerDelegate, PDFViewDelegate, ActionMenuViewControllerDelegate, OutlineViewControllerDelegate, MFMailComposeViewControllerDelegate {
#IBOutlet weak var btn: UIButton!
var pdfDocument: PDFDocument?
#IBOutlet weak var pdfView: PDFView!
#IBOutlet weak var webview: UIWebView!
override func viewDidLoad() {
super.viewDidLoad()
pdfView.autoScales = true
pdfView.displayMode = .singlePage
pdfView.displayDirection = .horizontal
pdfView.usePageViewController(true, withViewOptions: [UIPageViewControllerOptionInterPageSpacingKey: 20])
pdfView.document = pdfDocument
resume()
// ActivityViewController
}
override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) {
coordinator.animate(alongsideTransition: { (context) in
}, completion: nil)
}
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
return .none
}
func actionMenuViewControllergmailDocument(_ actionMenuViewController: ActionMenuViewController) {
}
func actionMenuViewControllerShareDocument(_ actionMenuViewController: ActionMenuViewController) {
}
func actionMenuViewControllerPrintDocument(_ actionMenuViewController: ActionMenuViewController) {
}
func outlineViewController(_ outlineViewController: OutlineViewController, didSelectOutlineAt destination: PDFDestination) {
resume()
pdfView.go(to: destination)
}
private func resume() {
let backButton = UIBarButtonItem(image: #imageLiteral(resourceName: "Chevron"), style: .plain, target: self, action: #selector(back(_:)))
let actionButton = UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(showActionMenu(_:)))
navigationItem.leftBarButtonItems = [backButton, actionButton]
pdfView.isHidden = false
}
#objc func resume(_ sender: UIBarButtonItem) {
resume()
}
#objc func back(_ sender: UIBarButtonItem) {
navigationController?.popViewController(animated: true)
}
#objc func showActionMenu(_ sender: UIBarButtonItem) {
if let viewController = storyboard?.instantiateViewController(withIdentifier: String(describing: ActionMenuViewController.self)) as? ActionMenuViewController {
let activityVC = UIActivityViewController(activityItems: [self.pdfDocument!], applicationActivities: nil)
activityVC.popoverPresentationController?.sourceView = self.view
self.present(activityVC, animated: true, completion: nil)
}
}
}
In SWIFT 4
#IBAction func sharePDF(_ sender: : Any) {
let fm = FileManager.default
var pdfURL = (fm.urls(for: .documentDirectory, in: .userDomainMask)).last! as URL
pdfURL = pdfURL.appendingPathComponent("GridLines.pdf") as URL
//Rename document name to "Hello.pdf"
let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("Hello.pdf") as NSURL
do {
let data = try Data(contentsOf: pdfURL)
try data.write(to: url as URL)
let activitycontroller = UIActivityViewController(activityItems: [url], applicationActivities: nil)
if activitycontroller.responds(to: #selector(getter: activitycontroller.completionWithItemsHandler))
{
activitycontroller.completionWithItemsHandler = {(type, isCompleted, items, error) in
if isCompleted
{
print("completed")
}
}
}
activitycontroller.excludedActivityTypes = [UIActivityType.airDrop]
activitycontroller.popoverPresentationController?.sourceView = self.view
self.present(activitycontroller, animated: true, completion: nil)
}
catch {
//ERROR
}
}
You can also share the PDF data itself using the dataRepresentation() function
guard let data = document?.dataRepresentation() else { return }
let activityController = UIActivityViewController(activityItems: [data], applicationActivities: nil)
present(activityController, animated: true)
Cheers
Try like this
let fileManager = FileManager.default
let docsurl = try! fileManager.url(for:.documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
let documentoPath = docsurl.appendingPathComponent("yourfile.pdf")
if fileManager.fileExists(atPath: documentoPath){
let pdfData = NSData(contentsOfFile: documentoPath)
var activityViewController = UIActivityViewController(activityItems: ["Your title that you wanna share", pdfData], applicationActivities: nil) // and present it
present(activityViewController, animated: true) {() -> Void in }
}
Its working fine ... I use it .
You already have a PDFDocument object, so reconstructing the file url is unnecessary. Simply pass your PDFDocument's documentURL property instead:
let activityVC = UIActivityViewController(activityItems: [self.pdfDocument!.documentURL!], applicationActivities: nil)
Try with this
let fileManager = FileManager.default
let docsurl = try! fileManager.url(for:.documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
let documentoPath = docsurl.appendingPathComponent("documento.pdf")
if fileManager.fileExists(atPath: documentoPath){
let documento = NSData(contentsOfFile: documentoPath)
let activityViewController: UIActivityViewController =
UIActivityViewController(activityItems: [documento!],
applicationActivities: nil)
activityViewController.popoverPresentationController?.sourceView=self.view
present(activityViewController, animated: true, completion: nil)
}
else {
print("document was not found")
}
Call this method on button click
func sharePdf() {
let activityViewController = UIActivityViewController(activityItems: [pdfView.document!.dataRepresentation()!], applicationActivities: nil)
present(activityViewController, animated: true)
}
For sharing image just change the activity item
func shareImg() {
let activityViewController = UIActivityViewController(activityItems: [imageView.image!], applicationActivities: nil)
present(activityViewController, animated: true)
}
You can share multiple items at once, by adding it in activityItems array

How to get and show screenshot in share button?

Below I have tried to code so the screenShot function will take a full screenshot of my viewController. I am trying to figure out how I could take the screenshot and put it in into my activityItems in the sharePressed action, so it will show the screenshot when you try to share.
func captureScreen() -> UIImage? {
UIGraphicsBeginImageContextWithOptions(view.bounds.size, false, UIScreen.main.scale)
view.layer.render(in: UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
#IBAction func sharePressed(_ sender: Any) {
let activityVC = UIActivityViewController(activityItems: [""], applicationActivities: nil)
activityVC.popoverPresentationController?.sourceView = self.view
self.present(activityVC, animated: true, completion: nil)
}
#IBAction func sharePressed(_ sender: Any) {
let imgScreenshot = captureScreen()
if let imgScreenshot = imgScreenshot {
let objectsToShare = ["Post message", imgScreenshot] as [Any]
let activityVC = UIActivityViewController(activityItems: objectsToShare, applicationActivities: nil)
activityVC.excludedActivityTypes = [UIActivityType.airDrop, UIActivityType.addToReadingList]
self.present(activityVC, animated: true, completion: nil)
}
}

There's a bug in CNContactPickerController

After spending all day (>12 hours) trying to isolate a bug in 13 lines of mind-bogglingly generic code, I have come to the dubious conclusion that there must be a bug in the current iteration of CNContactPickerViewController, in iOS 9.2.
Simply copy+paste this ViewController and link the invite action to a button.
The bug is that MFMessageComposeViewController dismisses itself immediately.
If anybody knows what to do with this, do share?
import UIKit
import MessageUI
import ContactsUI
class ViewController: UIViewController, MFMessageComposeViewControllerDelegate, CNContactPickerDelegate {
let contactPickerVC = CNContactPickerViewController()
let messageVC = MFMessageComposeViewController()
override func viewDidLoad() {
super.viewDidLoad()
contactPickerVC.delegate = self
}
func contactPicker(picker: CNContactPickerViewController, didSelectContact contact: CNContact) {
if let phoneNumberValue = contact.phoneNumbers.first?.value as? CNPhoneNumber {
if let phoneNumber = phoneNumberValue.valueForKey("digits") as? String {
// Configure message ViewController
messageVC.messageComposeDelegate = self
messageVC.recipients = [phoneNumber]
messageVC.body = "Yoyoyo"
picker.presentViewController(messageVC, animated: true, completion: nil)
}
}
}
func messageComposeViewController(controller: MFMessageComposeViewController, didFinishWithResult result: MessageComposeResult) {
controller.dismissViewControllerAnimated(true, completion: nil)
}
#IBAction func invite(sender: AnyObject) {
presentViewController(contactPickerVC, animated: true, completion: nil)
}
}
I got it working by dismissing the pickerVC and changing the controller which presents the messageVC!
Insert (before the messageVC config lines):
picker.dismissViewControllerAnimated(true, completion: nil)
Replace
picker.presentViewController(messageVC, animated: true, completion: nil)
with
presentViewController(messageVC, animated: true, completion: nil)

Resources