MFMailComposeViewController Interactive Dismiss Not Working On iOS 16

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

  1. A custom swiftui view in sheet has interactive dismiss
  2. 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.

MFMailComposeViewController Interactive Dismiss Not Working On iOS 16
 
 
Q