SwiftUI:使用MFMailComposeViewController发送电子邮件

4
我正在尝试在我的SwiftUI应用程序中实现“发送电子邮件”按钮,使用SwiftUI生命周期并针对iOS 14进行目标设置。
我知道网上有很多解决方案-在这里和其他地方都有。然而,到目前为止我还没有能够让任何东西在模拟器/设备上工作。
我的当前解决方案看起来像这样(基于这个stackoverflow问题
import SwiftUI
import MessageUI
import Foundation

struct ContentView: View {

    class MailComposeViewController: UIViewController, MFMailComposeViewControllerDelegate {
    
        static let shared = MailComposeViewController()
    
        func sendEmail() {
            if MFMailComposeViewController.canSendMail() {
                let mail = MFMailComposeViewController()
                mail.mailComposeDelegate = self
                mail.setToRecipients(["test@test.com"])

                UIApplication.shared.windows.last?.rootViewController?.present(mail, animated: true, completion: nil)
            } else {
                // Alert
            }
        }
    
        func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
            controller.dismiss(animated: true, completion: nil)
        }
    }
    
    var body: some View {
        Button(action: {
            MailComposeViewController.shared.sendEmail()
        }, label: {
            Text("Send")
        })
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

模拟器显示了按钮,并且没有任何错误提示。但是,点击按钮时什么也不会发生 - 在设备上测试时也是同样的情况。有什么想法吗?谢谢!
2个回答

2
你的代码能正常运行,问题在于iOS模拟器没有Mail应用程序,因此MFMailComposeViewController.canSendMail()返回false。请在真实设备上尝试,这样它就可以工作了。你没有看到任何错误的原因是因为这段代码:
if MFMailComposeViewController.canSendMail() {
                let mail = MFMailComposeViewController()
                mail.mailComposeDelegate = self
                mail.setToRecipients(["test@test.com"])

                UIApplication.shared.windows.last?.rootViewController?.present(mail, animated: true, completion: nil)
            } else {
                // Alert
            }

else块内,不要仅仅暂时注释掉// Alert,而是在调试时打印一些东西,这将使您的生活变得更加轻松。

我已经意识到可能是这种情况,并在我的(实体)iPhone 上进行了测试。然而,我遇到了相同的问题。 - Malburrito
1
@Malburrito 我刚刚测试了你的代码,没有做任何修改,它运行正常。请确保你的设备上完全设置了iOS Mail应用程序,以便MFMailComposeViewController.canSendMail()返回true。 - Arjun
谢谢您再次在您的设备上进行测试!我犯了个错误,认为任何电子邮件应用程序(例如Outlook或Gmail)都会被触发。但似乎它只适用于苹果的Mail应用程序。当该应用程序安装在测试设备上时,它可以正常工作。 您是否知道如何修改代码以使其与iOS 14中用户可以设置的“默认”电子邮件应用程序一起使用? - Malburrito
1
很遗憾,目前似乎还无法实现这一点:https://developer.apple.com/forums/thread/653146不过你可以创建一个mailto链接按钮。虽然无法插入主题或正文内容,但它会打开默认的邮件应用程序:https://dev59.com/oF8e5IYBdhLWcg3wNIJp - Arjun
1
谢谢 @Arjun - 这正是我选择的解决方案。实际上,甚至可以通过mailto:链接传递一个主题(至少在Gmail中效果很好)。如果感兴趣,请在我下面发布的答案中找到我的当前解决方案。 - Malburrito

2

在我最初的问题中共享的代码片段的基础上进行构建:

根据@Arjun的答案,这是我当前的解决方法,以考虑某些人可能已经删除了Apple Mail应用并正在使用另一个电子邮件应用程序的边缘情况:

Button(action: {
    if MailComposeViewController.shared.canSendMail() {
        MailComposeViewController.shared.sendEmail()
    } else {
        openURL(URL(string: "mailto:someone@example.com?subject=This%20is%20the%20subject")!)
    }
}, label: {
    Text("Send")
})

只要用户设置了苹果邮件,就会打开应用内的邮件列表,否则会使用mailto链接切换到其他任何电子邮件应用程序。

1
thisIsTest() 做什么? - meaning-matters
那是一个错误...我刚刚替换成了正确的代码。 - Malburrito
这个不应该作为批准答案,因为它非常不正确。MailComposeViewController 应该是 MFMailComposeViewController,需要导入 MessageUI,并且 sendEmail() 甚至不是一个现有的方法。 文档:https://developer.apple.com/documentation/messageui/mfmailcomposeviewcontroller - albertodebortoli

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接