Часто бывает необходимо добавить функцию отправки электронной почты в приложения для iOS. Для этого существует специальный контроллер представления, который называется MFMailComposeViewController. При представлении он вызывает знакомый системный контроллер для составления и отправки электронного письма. Перед его представлением можно указать значения по умолчанию, такие как тема или получатели, даже предварительно определенное тело электронной почты. В целом, отправка электронной почты — довольно стандартная процедура, и этот пост проведет вас через этапы интеграции компоновщика электронной почты на iOS.

Начальные шаги

Первым шагом к представлению системного контроллера для составления и отправки электронных писем является импорт определенной платформы, которая сделает доступным класс MFMailComposeViewController. Это MessageUI:

import MessageUI

После этого обязательно проверьте, действительно ли устройство может отправлять электронные письма! Если мы пропустим это и устройство по какой-то причине не сможет отправлять электронные письма, приложение просто выйдет из строя; это то, чего мы ни в коем случае не хотим.

Выполнить эту проверку легко, и все, что для этого нужно, — это вызвать метод класса в MFMailComposeViewController:

func composeEmail() {
    guard MFMailComposeViewController.canSendMail() else {
        let alert = UIAlertController(title: "Send email", message: "This device cannot send emails.", preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
 
        self.present(alert, animated: true, completion: nil)
        return       
    }
}

Предположим, что метод composeEmail() — это место для инициализации экземпляра MFMailComposeViewController и его модального представления в приложении. Обратите внимание, что он начинается с вызова метода canSendMail() и проверки способности устройства отправлять электронные письма. Если нет, то в этом примере мы просто представляем оповещение, сообщающее об этом, и возвращаемся из метода. В реальном мире делайте все, что подходит вашему приложению, чтобы справиться с этим случаем.

Инициализация и настройка экземпляра почтового компоновщика

Минимальная реализация, необходимая для создания и настройки экземпляра MFMailComposeViewController, разделена следующими двумя строками:

let email = MFMailComposeViewController()
email.mailComposeDelegate = self

Текущий экземпляр контроллера представления устанавливается как делегат почтового контроллера. Однако обратите внимание на свойство экземпляра email, которое мы используем для этого; свойство делегата называется mailComposeDelegate. Есть только один метод делегата, который нужно реализовать, и мы займемся им через некоторое время.

Прежде чем представить контроллер компоновщика электронной почты, можно установить предопределенные значения для различных полей электронной почты. Мы можем сделать это только для нескольких или для всех полей, в зависимости от потребностей приложения. Давайте посмотрим их один за другим.

Первый — это установка темы письма. Просто предоставьте его в качестве строкового аргумента методу setSubject(), доступному через объект email:

email.setSubject("New post on my site!")

Чтобы указать одного или нескольких получателей, просто передайте в качестве аргумента массив строковых значений следующему методу, где каждое значение является адресом электронной почты получателя:

email.setToRecipients(["[email protected]", "[email protected]", "[email protected]"])

Обратите внимание, что пользователи могут добавить больше адресов, если захотят. Аналогичным образом мы также можем предоставить адреса для полей «Копия» и «Скрытая копия» электронной почты. Для этого используйте setCcRecipients() и setBccRecipients() соответственно.

Также можно установить адрес в поле «От» электронной почты следующим образом:

email.setPreferredSendingEmailAddress("[email protected]")

Прежде чем представить составитель электронной почты, мы можем предоставить предопределенное тело. Нам просто нужно вызвать метод setMessageBody(_:isHTML:), указав фактическое содержимое сообщения в качестве первого аргумента, и будет ли это содержимое простым текстом или HTML:

email.setMessageBody("This is a sample message!", isHTML: false)

Как только вы закончите указывать значения по умолчанию, используя любой из методов, продемонстрированных выше, не забудьте представить почтовый контроллер:

self.present(email, animated: true, completion: nil)

Следующий метод содержит все это в одном месте:

func composeEmail() {
    guard MFMailComposeViewController.canSendMail() else {
        let alert = UIAlertController(title: "Send email", message: "This device cannot send emails.", preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
        self.present(alert, animated: true, completion: nil)
        return        
    }
    
    let email = MFMailComposeViewController()
    email.mailComposeDelegate = self
    
    // Set email subject.
    email.setSubject("New post on my site!")
    
    // Set recipients.
    email.setToRecipients(["[email protected]", "[email protected]", "[email protected]"])
 
    // Set the From field email address.
    email.setPreferredSendingEmailAddress("[email protected]")
    
    // Set email body.
    email.setMessageBody("This is a sample text!", isHTML: false)
    
    // Present the email compose view controller.
    self.present(email, animated: true, completion: nil)
}

Метод делегата

Независимо от того, будете ли вы устанавливать значения по умолчанию для полей электронной почты или нет, реализация единственного доступного метода делегата — это то, что вы всегда должны делать. Причина этого в том, что в этом методе мы можем определить две вещи:

  • что пользователь сделал с письмом, и, следовательно, продолжить дальнейшие действия, если это необходимо,
  • проверьте, не произошла ли ошибка и электронное письмо не было отправлено.

Как приложение должно реагировать в любом из вышеперечисленных случаев, зависит от требований приложения. Например, вы можете захотеть отобразить предупреждение в случае ошибки или выполнить операции, связанные с пользовательским интерфейсом, после успешной отправки электронного письма.

В следующем фрагменте вы можете увидеть пример реализации метода делегата, который имеет место в расширении контроллера представления. Реальной обработки не происходит, есть только команды печати для демонстрации каждого случая:

extension UIViewController: MFMailComposeViewControllerDelegate {
    public func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {        
        guard error == nil else {
            print(error!.localizedDescription)
            controller.dismiss(animated: true, completion: nil)
            return
        }
        
        switch result {
            case .sent: print("The email was sent")
            case .saved: print("The email was saved")
            case .cancelled: print("The email was cancelled")
            case .failed: print("Failed to send email")
            @unknown default: break
        }
        
        controller.dismiss(animated: true, completion: nil)
    }
}

Обратите внимание, что значение параметра result содержит четыре варианта, которые указывают, было ли электронное письмо отправлено, сохранено, отменено пользователем или по какой-то причине не удалось отправить. В оператор switch также необходимо добавить случай по умолчанию, покрывающий будущие потенциальные значения.

В конце концов, контроллер электронной почты должен быть явно отклонен.

Резюме

Это было все о представлении компоновщика электронной почты на iOS; простая задача, которую можно описать двумя способами; composeEmail(), продемонстрированный ранее, и метод делегата прямо выше. В этом посте я показал вам, как представить редактор электронной почты в UIKit. В следующем посте я покажу, как сделать то же самое в SwiftUI. Спасибо за чтение, и берегите себя!

Первоначально опубликовано на https://serialcoder.dev 4 июня 2021 г.