1

Context: I have an app with table view for equipment specifications. Right now, each table view has a "view" and "share" button for the user to interact with the PDF version of the spec sheet. The view button opens the PDF in a web view, the email button adds the pdf as an attachment- both work great. I wanted to remove the need for two buttons and simply have a share sheet. The share sheet works, but I am no longer programmatically setting the pdf's name.

Question: How to set a filename for files attached in mail via UIActivityViewController in a similar way to MailComposeViewController? Also, is it possible to programmatically CC the group email in UIActivityViewController?

Update: The file is located on our company's website. The only property that the app has is the URL location of the file. Everything works, I just want to control the inputs to the mail composer that the share sheet opens.

MailComposeViewController (working as expected)

    @IBAction func getSpecURLfromButton(_ sender: subclassedUIButton) {
    // Get the URL from the button
    buttonURL = sender.urlString!

    // Now Send the Email
    let composeVC = MFMailComposeViewController()
    composeVC.mailComposeDelegate = self

    // Configure the fields of the interface.
    //composeVC.setToRecipients(["name@doamin.com"])
    composeVC.setCcRecipients(["group@domain.com"])
    composeVC.setSubject("Spec Sheet Request")
    composeVC.setMessageBody("The requested spec sheet is attached.", isHTML: false)

    // Attach the spec sheet at button URL to the email
    // source: https://stackoverflow.com/questions/30423583/attach-a-pdf-file-to-email-swift


    let specURL = URL(string: buttonURL)
    if let fileData = NSData(contentsOf: specURL! as URL) {
        print("File data loaded.")
        composeVC.addAttachmentData( fileData as Data, mimeType: "application/pdf", fileName: "Tubular Spec Sheet")
    }
    //}

    // Present the view controller modally.
    self.present(composeVC, animated: true, completion: nil)

}

UIActivityViewController (works, but not naming file)

@IBAction func shareSpecButton(_ sender: UIBarButtonItem) {
    if let contentURL = URL(string: targetURL) {
        let content = NSData(contentsOf: contentURL)
        let sharedContent = [content]
        let activityViewController = UIActivityViewController(activityItems: sharedContent, applicationActivities: nil)
        activityViewController.popoverPresentationController?.sourceView = self.view // so that iPads won't crash

        // present the view controller
        self.present(activityViewController, animated: true, completion: nil)
    }
}
Brennan
  • 504
  • 3
  • 14
  • Try setting `sharedContent` to `[contentURL]` instead of `[content]`. In other words, share the URL instead of the data. – rmaddy Sep 18 '17 at 21:25
  • I did that at first, it wouldn't attach the PDF when mailing. The current method attaches a PDF, but I don't have control over the name of the attachment. Or the email subject. Or recipients. – Brennan Sep 18 '17 at 21:27
  • 1
    It should work as a URL if it is a local file URL. – rmaddy Sep 18 '17 at 21:29
  • Unrelated but why are you using `NSData` in Swift? Just use `Data`. – rmaddy Sep 18 '17 at 21:30
  • Sorry for the confusion, but the file is not local. It is on our company website. – Brennan Sep 18 '17 at 21:31
  • Using NSData because I found that somewhere on this site and it works. lol. I'm a mechanical engineer, so the app dev stuff is more of a side gig for me. – Brennan Sep 18 '17 at 21:33
  • You could write the data to a local file and use the local URL with the UIActivityViewController. – rmaddy Sep 18 '17 at 21:33
  • Thanks, I'll give that a try. Will that give me the ability to programmatically assign values to the MailComposeViewController that the UIActivityViewController opens? – Brennan Sep 18 '17 at 21:37
  • `NSData` calls `func activityViewController(_ activityViewController: UIActivityViewController, dataTypeIdentifierForActivityType activityType: UIActivityType?) -> String` to set contentType on activity item, `Data` - not. At least in Swift 4. – Deniss Fedotovs Dec 12 '17 at 15:22

1 Answers1

1

The workaround I've used is to use the UIAlertController with the options I want the user to have. This gives me the option to run the function that was working to send an email.

    @IBAction func shareSpecButton(_ sender: UIBarButtonItem) {
     if let contentURL = URL(string: targetURL) {
        sendMailViaActionSheet(fileURL: contentURL)
     }
    }

 private func sendMail (fileURL: URL) {

    let composeVC = MFMailComposeViewController()
    composeVC.mailComposeDelegate = self

    // Configure the fields of the interface.
    //composeVC.setToRecipients(["user@domain.com"])
    composeVC.setCcRecipients(["group@domain.com"])
    composeVC.setSubject("Spec Sheet Request")
    composeVC.setMessageBody("The requested spec sheet is attached.", isHTML: false)

    if let fileData = NSData(contentsOf: fileURL as URL) {
        print("File data loaded.")
        composeVC.addAttachmentData( fileData as Data, mimeType: "application/pdf", fileName: "Tubular Spec Sheet")
    }
    //}

    // Present the view controller modally.
    self.present(composeVC, animated: true, completion: nil)


}

Alert Controller Setup:

private func sendMailViaActionSheet (fileURL: URL) {

    // Set up Alert Controller
    var alert = UIAlertController(
        title: "Share Spec Sheet",
        message: "Choose a method to share the spec sheet ",
        preferredStyle: .actionSheet
    )

    // First Action
    alert.addAction(UIAlertAction(
        title: "Send pdf in an email",
        style: UIAlertActionStyle.default)
    { (action: UIAlertAction) -> Void in
        // code to execute when action is chosen

        // Send pdf as data file
        self.sendMail(fileURL: fileURL)
        }
    )

    // Second Action
    alert.addAction(UIAlertAction(
        title: "Send link in an email",
        style: UIAlertActionStyle.default)
    { (action: UIAlertAction) -> Void in
        // code to execute when action is chosen
        }
    )

    // Cancel Action
    alert.addAction(UIAlertAction(
        title: "Cancel",
        style: .cancel)
    { (action: UIAlertAction) -> Void in
        // do nothing
        }
    )

    // Present the action sheet
    present( alert, animated: true, completion: nil)
}
Brennan
  • 504
  • 3
  • 14