swift - dismissing mail view controller from Sprite Kit - swift

I am trying to add a send email button to a Sprite Kit game. I can get the email dialog to show up. But if I hit cancel, the app will crash or do nothing. If I hit send, the email will send, but the dialog stays. I cannot get the mailComposeController function to fire...please help!
Code:
import Foundation
import UIKit
import MessageUI
class MailViewController: UIViewController, MFMailComposeViewControllerDelegate {
let systemVersion = UIDevice.currentDevice().systemVersion
let devicemodel = UIDevice.currentDevice().model
let appVersion = NSBundle.mainBundle().infoDictionary?["CFBundleShortVersionString"] as! String
let appBuild = NSBundle.mainBundle().infoDictionary?["CFBundleVersion"] as! String
let myrootview2 = UIApplication.sharedApplication().keyWindow?.rootViewController
let mailComposerVC = MFMailComposeViewController()
override func viewDidLoad() {
super.viewDidLoad()
}
func sendEmailButtonTapped(sender: AnyObject) {
let mailComposeViewController = configuredMailComposeViewController()
if MFMailComposeViewController.canSendMail() {
self.view.window?.rootViewController = mailComposerVC
print("This is the rootview2: \(myrootview2)")
myrootview2!.presentViewController(mailComposeViewController, animated: true, completion: nil)
} else {
self.showSendMailErrorAlert()
}
}
func configuredMailComposeViewController() -> MFMailComposeViewController {
var msgbody: String
mailComposerVC.mailComposeDelegate = self
msgbody = "\n\nDevice: \(devicemodel)\niOS Version: \(systemVersion)\nApp Version: \(appVersion)\nApp Build Number: \(appBuild)\n"
mailComposerVC.setToRecipients(["test1#test.com"])
mailComposerVC.setSubject("test subject")
mailComposerVC.setMessageBody(msgbody, isHTML: false)
//print(mailComposerVC)
return mailComposerVC
}
func showSendMailErrorAlert() {
let sendMailErrorAlert = UIAlertView(title: "Could Not Send Email", message: "Your device could not send e-mail. Please check e-mail configuration and try again.", delegate: self, cancelButtonTitle: "OK")
sendMailErrorAlert.show()
}
// THIS DOESN'T GET CALLED WHEN SENDING OR CANCELLING EMAIL!
func mailComposeController(controller: MFMailComposeViewController, didFinishWithResult result: MFMailComposeResult, error: NSError?) {
let test1 = result.rawValue
print(test1)
print(controller)
print(self)
print(myrootview2)
}

The issue is you are making the mailVC as the root view, you have to present it on your view like given below
#IBAction func sendEmailButtonTapped(sender: AnyObject) {
let mailComposeViewController = configuredMailComposeViewController()
if MFMailComposeViewController.canSendMail() {
self.presentViewController(mailComposeViewController, animated: true, completion: nil)
} else {
self.showSendMailErrorAlert()
}
}
 func mailComposeController(controller: MFMailComposeViewController!, didFinishWithResult result: MFMailComposeResult, error: NSError!) {
controller.dismissViewControllerAnimated(true, completion: nil)
}

Related

Add & Cancel buttons in EventKit not working

Im using event kit to create a reminder, but when I press add or cancel the window does not close. if I go into the calendars app I can see the item in there. I've tried adding "editviewDelegate = self" but I always get an error saying "Cannot assign value of type 'ViewController?' to type 'EKEventEditViewDelegate"
import UIKit
import EventKit
import EventKitUI
class ViewController: UIViewController, EKEventViewDelegate {
func eventViewController(_ controller: EKEventViewController, didCompleteWith action: EKEventViewAction) {
controller.dismiss(animated: true, completion: nil)
}
let store = EKEventStore()
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(addnew))
}
#objc func addnew() {
store.requestAccess(to: .event) { [weak self] success, error in
if success, error == nil {
DispatchQueue.main.async {
guard let store = self?.store else {return}
let othervc = EKEventEditViewController()
othervc.eventStore = store
othervc.event = EKEvent(eventStore: store)
self?.present(othervc, animated: true, completion: nil)
}
}
}
}

How to dismiss MFMailComposeViewController from class mail?

I have separated the mail functions from my UIviewController and placed them into a class ‘Mail’. Works fine, but now I do have trouble to dismiss my ‘MFMailComposeViewController’. The delegate ‘mailComposeController’ is not called, Any ideas how to fix?
import Foundation
import MessageUI
class Mail: UIViewController, MFMailComposeViewControllerDelegate{
static func createMail2(
fromViewController:UIViewController,
recipients :String,
messageTitle:String,
messageText :String,
attachment :AnyObject?)
{
if MFMailComposeViewController.canSendMail() {
let mail = MFMailComposeViewController()
//mail.mailComposeDelegate = self //Cannot assign value of type 'Mail.Type' to type 'MFMailComposeViewControllerDelegate?'
mail.mailComposeDelegate? = fromViewController as! MFMailComposeViewControllerDelegate //added ? (optional)
mail.setToRecipients([recipients]) //(["mail#to.me"])
mail.setSubject(messageTitle) //("your subject text")
mail.setMessageBody(messageText, isHTML: false)
//ggf. Attachment beifügen>>>
if attachment != nil {
//attachment vorhanden, also anhängen
let attachName = "\(messageTitle).pdf"
mail.addAttachmentData(
attachment as! Data,
mimeType: "application/octet-stream", //für binäre Daten, funktioniert immer
fileName: attachName)
}//end if attachment
//<<<ggf. Attachment beifügen
// Present the view controller modally
fromViewController.present(mail, animated: true) //show mail
} else {
// show failure alert
print("Mail services are not available")
let alert = UIAlertController(title: "Mail error", message: "Your device has not been configured to send e-mails", preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: .default, handler: nil)
alert.addAction(okAction)
fromViewController.present(alert,animated: true, completion: nil)
}//end if else
}//end func createMail
//mail delegate
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
//It’s called when the user dismisses the controller, either by sending the email or canceling the action. Either way, you have to dismiss the controller manually.
//ggf. noch aktionen...
controller.dismiss(animated: true) //remove the mail view
}//end func mailComposeController
}//end class Mail
What you need is to create a static shared instance of your Mail controller and set if as the mailComposeDelegate. You should also create a controller property in your mail controller to keep a reference of the view controller that has invoked the mail composer and declare your createMail as an instance method (not static):
import UIKit
import MessageUI
class MailComposer: NSObject, MFMailComposeViewControllerDelegate {
static let shared = MailComposer()
private var controller: UIViewController?
func compose(controller: UIViewController, recipients: String,
messageTitle: String, messageText: String, fileURL: URL? = nil) { //, completion: #escaping ((MFMailComposeResult, Error?) -> Void)) {
self.controller = controller
if MFMailComposeViewController.canSendMail() {
let mail = MFMailComposeViewController()
mail.mailComposeDelegate = MailComposer.shared
mail.setToRecipients([recipients])
mail.setSubject(messageTitle)
mail.setMessageBody(messageText, isHTML: false)
if let fileURL = fileURL {
do {
try mail.addAttachmentData(Data(contentsOf: fileURL), mimeType: "application/octet-stream", fileName: fileURL.lastPathComponent)
} catch {
print(error)
}
}
controller.present(mail, animated: true)
} else {
let alertController = UIAlertController(title: "Mail Compose Error",
message: "Your device has not been configured to send e-mails",
preferredStyle: .alert)
alertController.addAction(.init(title: "OK", style: .default) { _ in
alertController.dismiss(animated: true)
})
controller.present(alertController, animated: true)
}
}
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
// You should switch the result only after dismissing the controller
controller.dismiss(animated: true) {
let message: String
switch result {
case .sent: message = "Message successfully sent!"
case .saved: message = "Message saved!"
case .cancelled: message = "Message Canceled!"
case .failed: message = "Unknown Error!"
#unknown default: fatalError()
}
let alertController = UIAlertController(title: "Mail Composer",
message: message,
preferredStyle: .alert)
alertController.addAction(.init(title: "OK", style: .default) { _ in
alertController.dismiss(animated: true)
})
self.controller?.present(alertController, animated: true) {
self.controller = nil
}
}
}
}
Usage:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let recipients = "user#email.com"
let messageTitle = "New Message"
let messageText = "Mail Test"
MailComposer.shared.compose(controller: self, recipients: recipients, messageTitle: messageTitle, messageText: messageText)
}
}
The UIViewController that you're passing as the parameter for fromViewController should conform to MFMailComposeViewControllerDelegate protocol and you should be implementing mailComposeController(_: didFinishWith: in the definition of that controller.
class Mail: UIViewController {
static func createMail2(
fromViewController: UIViewController,
recipients :String,
messageTitle:String,
messageText :String,
attachment :AnyObject?) {
if MFMailComposeViewController.canSendMail() {
let mail = MFMailComposeViewController()
if let fromViewController = fromViewController as? MFMailComposeViewControllerDelegate {
mail.mailComposeDelegate = fromViewController
} else {
print("fromViewController needs to conform to MFMailComposeViewControllerDelegate")
}
//...
}
}
}

Can't close mail view controller when clicking Cancel, Save Draft or Delete Draft

I'm implementing a mail controller in my app but I can't figure out why it won't close when clicking save draft or delete draft. The window gets stuck on the email screen and I can't click "Cancel" a second time either.
#IBAction func emailButtonTapped(_ sender: UIButton) {
guard MFMailComposeViewController.canSendMail() else {
if !MFMailComposeViewController.canSendMail() {
print("Can not send email")
return
}
return
}
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
dismiss(animated: true, completion: nil)
}
let mailComposer = MFMailComposeViewController()
mailComposer.mailComposeDelegate = self
mailComposer.setToRecipients(["example#example.com"])
mailComposer.setSubject("Look at this")
mailComposer.setMessageBody("Hello, this is an email from the app I made.", isHTML: false)
present(mailComposer, animated: true, completion: nil)
}
I successfully fixed the issue, and it was a pretty stupid one!
Some code was outside the emailButtonTapped func:
#IBAction func emailButtonTapped(_ sender: UIButton) {
//guard MFMailComposeViewController.canSendMail() else {
if !MFMailComposeViewController.canSendMail() {
print("Can not send email")
return
}
let mailComposer = MFMailComposeViewController()
mailComposer.mailComposeDelegate = self
mailComposer.setToRecipients(["example#example.com"])
mailComposer.setSubject("Look at this")
mailComposer.setMessageBody("Hello, this is an email from the app I made.", isHTML: false)
present(mailComposer, animated: true, completion: nil)
}
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
dismiss(animated: true, completion: nil)
}
Swift 4
// MARK: - SEND EMAIL BUTTON
#IBAction func SendEmailButt(_ sender: AnyObject) {
// This string containes standard HTML tags, you can edit them as you wish
let messageStr = "Hello,"
let mailComposer = MFMailComposeViewController()
mailComposer.mailComposeDelegate = self
mailComposer.setSubject("Title")
mailComposer.setMessageBody(messageStr, isHTML: true)
if MFMailComposeViewController.canSendMail() { present(mailComposer, animated: true, completion: nil)
} else {
print("Your device cannot send emails. Please configure an email address into Settings -> Mail, Contacts, Calendars.")
}
}
// Email delegate
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
var resultMess = ""
switch result.rawValue {
case MFMailComposeResult.cancelled.rawValue:
resultMess = "Mail cancelled"
case MFMailComposeResult.saved.rawValue:
resultMess = "Mail saved"
case MFMailComposeResult.sent.rawValue:
resultMess = "Thanks for contacting us!\nWe'll get back to you asap."
case MFMailComposeResult.failed.rawValue:
resultMess = "Something went wrong with sending Mail, try again later."
default:break
}
// Show email result alert
print(resultMess)
dismiss(animated: true, completion: nil)
}
Can you try this once instead:
func mailComposeController(controller: MFMailComposeViewController, didFinishWithResult result: MFMailComposeResult, error: NSError?) {
// Dismiss the mail compose view controller.
controller.dismissViewControllerAnimated(true, completion: nil)
}
Check the following Code.
#IBAction func sendEmailButtonTapped(sender: AnyObject) {
let mailComposeViewController = configuredMailComposeViewController()
if MFMailComposeViewController.canSendMail() {
self.presentViewController(mailComposeViewController, animated: true, completion: nil)
} else {
self.showSendMailErrorAlert()
}
}
func configuredMailComposeViewController() -> MFMailComposeViewController {
let mailComposerVC = MFMailComposeViewController()
mailComposerVC.mailComposeDelegate = self
mailComposerVC.setToRecipients([])
mailComposerVC.setSubject("Sending In-App Email")
mailComposerVC.setMessageBody("Sending Email through your app in Swift", isHTML: false)
return mailComposerVC
}
func showSendMailErrorAlert() {
let sendMailErrorAlert = UIAlertView(title: "Could Not Send Email", message: "Your device could not send Email. Please check Email configuration and try again.", delegate: self, cancelButtonTitle: "OK")
sendMailErrorAlert.show()
}
// MFMailComposeViewControllerDelegate Method
func mailComposeController(controller: MFMailComposeViewController!, didFinishWithResult result: MFMailComposeResult, error: NSError!) {
controller.dismissViewControllerAnimated(true, completion: nil)
}

UIButton does not bring up MFMailViewController

I'm having an error with a bit of code. I am new to this and I am trying to teach myself. I am finding most of my answers online but can't seem to find anything about this particular issue. I want to send an email within the app but anytime I press the email button, the MFMailViewController does not come up. It is like my UIButton isn't working. But I know I have it as an IBAction. Here is my code so far. Any help is much appreciated.
import UIKit
import MessageUI
class RequestService: UIViewController,MFMailComposeViewControllerDelegate {
#IBOutlet weak var CustomerName: UITextField!
#IBOutlet weak var emailButton: UIButton!
#IBAction func sendEmail(_ sender: UIButton) {
if !MFMailComposeViewController.canSendMail() {
print("Mail services are not available")
let ComposeVC = MFMailComposeViewController()
ComposeVC.mailComposeDelegate = self
ComposeVC.setToRecipients(["jwelch#ussunsolar.com"])
ComposeVC.setSubject("New Support Ticket")
ComposeVC.setMessageBody(CustomerName.text!, isHTML: false)
self.present(ComposeVC, animated: true, completion: nil)
}
func mailComposeController(controller: MFMailComposeViewController,didFinishWithResult result:MFMailComposeResult, error: NSError?) {
// Check the result or perform other tasks.
// Dismiss the mail compose view controller.
controller.dismiss(animated: true, completion: nil)
}
}
}
You made an error in the syntax in your sendMail function. The code you posted will only open the view controller if the device can't send mail. Change it to this:
#IBAction func sendEmail(_ sender: UIButton) {
if !MFMailComposeViewController.canSendMail() {
print("Mail services are not available")
return
}
let composeVC = MFMailComposeViewController()
composeVC.mailComposeDelegate = self
composeVC.setToRecipients(["jwelch#ussunsolar.com"])
composeVC.setSubject("New Support Ticket")
composeVC.setMessageBody(CustomerName.text!, isHTML: false)
self.present(composeVC, animated: true, completion: nil)
}
You only attempt to display the mail controller if the device can't send email. That's backwards.
#IBAction func sendEmail(_ sender: UIButton) {
if MFMailComposeViewController.canSendMail() {
print("Mail services are not available")
let ComposeVC = MFMailComposeViewController()
ComposeVC.mailComposeDelegate = self
ComposeVC.setToRecipients(["jwelch#ussunsolar.com"])
ComposeVC.setSubject("New Support Ticket")
ComposeVC.setMessageBody(CustomerName.text!, isHTML: false)
self.present(ComposeVC, animated: true, completion: nil)
}
}
func mailComposeController(controller: MFMailComposeViewController,didFinishWithResult result:MFMailComposeResult, error: NSError?) {
// Check the result or perform other tasks.
// Dismiss the mail compose view controller.
controller.dismiss(animated: true, completion: nil)
}
And you need the delegate method outside of the other method.

MFMailComposeViewController disappear immediately under iOS9

Once I present my MFMailComposeViewController it is dismissed with error:
viewServiceDidTerminateWithError: Error Domain=_UIViewServiceInterfaceErrorDomain Code=3 "(null)" UserInfo={Message=Service Connection Interrupted}
What is going on?
VERY IMPORTANT NOTE
It is working very well under iOS8.
i can't help you since you did not post any code, but here is a working copy of a MailComposeController on iOS9, using it in my app without any problem. Important set your class conform to MFMailComposeViewControllerDelegate. Note that sendMail method is related to a button in my project
#IBAction func sendMail(sender: AnyObject) {
let mailComposeViewController = configuredMailComposeViewController()
if MFMailComposeViewController.canSendMail() {
self.presentViewController(mailComposeViewController, animated: true, completion: nil)
} else {
self.showSendMailErrorAlert()
}
}
func configuredMailComposeViewController() -> MFMailComposeViewController {
let mailComposerVC = MFMailComposeViewController()
mailComposerVC.mailComposeDelegate = self
mailComposerVC.setToRecipients(["yourMail#goesHere"])
return mailComposerVC
}
func showSendMailErrorAlert() {
print("There was an error.")
//In case of error with email account on device, you should implement an alert here
}
func mailComposeController(controller: MFMailComposeViewController, didFinishWithResult result: MFMailComposeResult, error: NSError?) {
controller.dismissViewControllerAnimated(true, completion: nil)
}