Posts

Post not yet marked as solved
0 Replies
172 Views
I am using MFMailComposeViewController to allow users to share in my app. Now my app is swiftUI so I had to wrap it in UIViewRepresentable. I have tied my mailComposeDelegate for dismissing as well. struct MailComposerView: UIViewControllerRepresentable { @Environment(\.presentationMode) var presentation @Binding var result: Result<MFMailComposeResult, Error>? var mailControllerWrapperBuilder: () -> MFMailComposerControllerWrappable = { MFMailComposeViewController() } let subject: String let body: String class Coordinator: NSObject, MFMailComposeViewControllerDelegate { @Binding var presentation: PresentationMode @Binding var result: Result<MFMailComposeResult, Error>? init(presentation: Binding<PresentationMode>, result: Binding<Result<MFMailComposeResult, Error>?>) { _presentation = presentation _result = result } func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) { defer { $presentation.wrappedValue.dismiss() } guard error == nil else { if let error = error { self.result = .failure(error) } else { self.result = .failure(NSError()) } return } self.result = .success(result) } } func makeCoordinator() -> Coordinator { return Coordinator(presentation: presentation, result: $result) } func makeUIViewController(context: UIViewControllerRepresentableContext<MailComposerView>) -> UIViewController { var mailComposer = mailControllerWrapperBuilder() mailComposer.setSubject(subject) mailComposer.setMessageBody(body, isHTML: false) mailComposer.mailComposeDelegate = context.coordinator return mailComposer.getUIViewController() } func updateUIViewController(_ uiViewController: UIViewController, context: UIViewControllerRepresentableContext<MailComposerView>) { } } protocol MFMailComposerControllerWrappable { var mailComposeDelegate: MFMailComposeViewControllerDelegate? { get set } var delegate: UINavigationControllerDelegate? { get set } func setSubject(_ subject: String) func setMessageBody(_ body: String, isHTML: Bool) func getUIViewController() -> UIViewController } extension MFMailComposeViewController: MFMailComposerControllerWrappable { func getUIViewController() -> UIViewController { self } } On my main view, which is a swiftui sheet, I present mail composer as a sheet. @State var showMail = false var body: some View { VStack { Button("Mail", action: { showMail = true }) } .sheet(isPresented: $showMail, content: { MailComposerView(result: $viewModel.mailResult, subject: "subject", body: "body") .presentationDetents([.large]) }) } On iOS 17 when swiping down, interactive dismiss is activated and shows user if they want to cancel sending mail. While on iOS16 this behaviour is not observed. I have tried following A custom swiftui view in sheet has interactive dismiss UIViewRespresentable of custom uiview has interactive dismiss Seems like this bug has to do with MFMailComposeViewController itself. Is there a known issue that was fixed in iOS 17? On other apple apps, this behaviour is not observed. One fix that I have on my mind is to present mailcomposer via rootcontroller and not rely on swiftui sheet.
Posted
by shjain.
Last updated
.