MailComposeView.swift (2050B)
1 import MessageUI 2 import SwiftUI 3 4 /// A plain-text attachment for a `MailComposeView`. 5 struct MailAttachment { 6 let data: Data 7 let mimeType: String 8 let fileName: String 9 10 /// Convenience for the common case: a UTF-8 `.txt` payload. 11 static func text(_ string: String, fileName: String) -> MailAttachment { 12 MailAttachment(data: Data(string.utf8), mimeType: "text/plain", fileName: fileName) 13 } 14 } 15 16 /// Wraps `MFMailComposeViewController` for presentation via `.sheet`. Callers 17 /// should gate presentation on `MFMailComposeViewController.canSendMail()` and 18 /// provide their own fallback when it returns false. 19 struct MailComposeView: UIViewControllerRepresentable { 20 let recipients: [String] 21 let subject: String 22 let body: String 23 var attachment: MailAttachment? 24 let onFinish: () -> Void 25 26 func makeCoordinator() -> Coordinator { 27 Coordinator(onFinish: onFinish) 28 } 29 30 func makeUIViewController(context: Context) -> MFMailComposeViewController { 31 let controller = MFMailComposeViewController() 32 controller.mailComposeDelegate = context.coordinator 33 controller.setToRecipients(recipients) 34 controller.setSubject(subject) 35 controller.setMessageBody(body, isHTML: false) 36 if let attachment { 37 controller.addAttachmentData( 38 attachment.data, 39 mimeType: attachment.mimeType, 40 fileName: attachment.fileName 41 ) 42 } 43 return controller 44 } 45 46 func updateUIViewController(_ controller: MFMailComposeViewController, context: Context) {} 47 48 final class Coordinator: NSObject, MFMailComposeViewControllerDelegate { 49 private let onFinish: () -> Void 50 51 init(onFinish: @escaping () -> Void) { 52 self.onFinish = onFinish 53 } 54 55 func mailComposeController( 56 _ controller: MFMailComposeViewController, 57 didFinishWith result: MFMailComposeResult, 58 error: Error? 59 ) { 60 onFinish() 61 } 62 } 63 }