SwiftUI表单数据生成PDF并发送至邮箱的实现方法咨询
实现方案
你可以直接用iOS系统自带的邮件发送组件实现需求,不需要额外搭建后端,适合新手快速落地:
前置说明
该方案会调用用户设备上已登录的系统邮件APP发送内容,不需要你处理邮箱账号密码、邮件服务配置等复杂逻辑,测试请用真机,模拟器没有预装邮件APP无法验证功能。
具体实现步骤
1. 封装邮件发送视图
SwiftUI没有原生的邮件发送组件,需要把UIKit的MFMailComposeViewController做一层兼容封装。
2. 格式化表单数据为邮件正文
把表单里的日期、开关、选择器等不同类型的变量统一转成可读的纯文本,作为邮件正文内容。
3. 新增发送按钮和触发逻辑
在导航栏添加发送按钮,点击后自动填充好收件人、主题、正文,用户确认后直接发送即可。
完整修改后代码
import SwiftUI // 新增:导入邮件框架 import MessageUI // 新增:封装SwiftUI可用的邮件发送视图 struct MFMailComposeView: UIViewControllerRepresentable { @Binding var isPresented: Bool let subject: String let recipients: [String] let body: String func makeUIViewController(context: Context) -> MFMailComposeViewController { let vc = MFMailComposeViewController() vc.setSubject(subject) vc.setToRecipients(recipients) vc.setMessageBody(body, isHTML: false) vc.mailComposeDelegate = context.coordinator return vc } func updateUIViewController(_ uiViewController: MFMailComposeViewController, context: Context) {} func makeCoordinator() -> Coordinator { Coordinator(isPresented: $isPresented) } class Coordinator: NSObject, MFMailComposeViewControllerDelegate { @Binding var isPresented: Bool init(isPresented: Binding<Bool>) { _isPresented = isPresented } func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) { isPresented = false } } // 检查设备是否支持邮件发送 static var canSendMail: Bool { MFMailComposeViewController.canSendMail() } } struct ContentView: View { // 原有表单变量不变 @State private var tournummer = "" @State private var fahrernachname = "" @State private var fahrervorname = "" @State private var fahrergeburtstag = Date() @State private var kundenachname = "" @State private var kundevorname = "" @State private var kundegeburtstag = Date() @State private var kilometerstand = "" @State private var warnweste = false @State private var anzahlschlüßel = 1 @State private var bereifung = "Winterreifen" // 新增:控制邮件弹窗显示的变量 @State private var showMailView = false // 新增:邮件发送失败提示变量 @State private var showMailErrorAlert = false // 新增:格式化日期的工具 private var dateFormatter: DateFormatter { let formatter = DateFormatter() formatter.dateFormat = "yyyy-MM-dd" return formatter } // 新增:自动拼接表单数据为邮件正文 private var mailBody: String { """ 工单信息: 工单编号:\(tournummer) 驾驶员信息: 姓:\(fahrernachname) 名:\(fahrervorname) 生日:\(dateFormatter.string(from: fahrergeburtstag)) 客户信息: 姓:\(kundenachname) 名:\(kundevorname) 生日:\(dateFormatter.string(from: kundegeburtstag)) 车辆信息: 公里数:\(kilometerstand) 车辆配置: 反光背心是否存在:\(warnweste ? "是" : "否") 钥匙数量:\(anzahlschlüßel) 轮胎类型:\(bereifung) """ } var body: some View { NavigationView{ Form { // 原有表单内容完全不变 Section(header: Text("Auftrags informationen")){ TextField("Tour Nummer", text: $tournummer) } Section(header: Text("Fahrer Daten")){ TextField("Nachname", text: $fahrernachname) TextField("Vorname", text: $fahrervorname) DatePicker("Geburtstag", selection: $fahrergeburtstag, displayedComponents: .date) } Section(header: Text("Kunden Daten")){ TextField("Nachname", text: $kundenachname) TextField("Vorname", text: $kundevorname) DatePicker("Geburtstag", selection: $kundegeburtstag, displayedComponents: .date) } Section(header: Text("Fahrzeug Daten")){ TextField("Kilometerstand", text: $kilometerstand) } Section(header: Text("Ausstattung")){ Toggle("Warnweste Vorhanden", isOn: $warnweste) Stepper("Schlüßel: \(anzahlschlüßel)", value: $anzahlschlüßel, in: 1...5) Picker( selection: $bereifung, label: Text("Bereifung:"), content: { Text("Winterreifen").tag("Winterreifen") Text("Sommerreifen").tag("Sommerreifen") Text("Allwetterreifen").tag("Allwetterreifen") }) } Section(header: Text("Fahrzeug Fotos")){ Text("fotos hier einfügen omar muss googlen wie das geht hahaha") } Section(header: Text("Hilfe und Service")){ Link("..-Logistik Webseite", destination: URL(string: "https://www.logistik....de")!) } Section(header: Text("®..-Logistik")){} } .navigationTitle("MM-Logistik Protokoll") .toolbar { ToolbarItemGroup(placement: .navigationBarTrailing){ // 新增:发送按钮 Button(action: { hideKeyboard() if MFMailComposeView.canSendMail { showMailView = true } else { showMailErrorAlert = true } }) { Image(systemName: "paperplane.fill") } Button{ hideKeyboard() } label: { Image(systemName:"chevron.down") } } } // 新增:绑定邮件弹窗 .sheet(isPresented: $showMailView) { MFMailComposeView( isPresented: $showMailView, subject: "工单数据:\(tournummer.isEmpty ? "未填写编号" : tournummer)", // 替换成你要发送的目标邮箱 recipients: ["target@example.com"], body: mailBody ) } // 新增:邮件不可用的提示弹窗 .alert("无法发送邮件", isPresented: $showMailErrorAlert) { Button("确定", role: .cancel) {} } message: { Text("请先在系统邮件APP中登录邮箱账号") } } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() .preferredColorScheme(.dark) .previewInterfaceOrientation(.portrait) } } // 原有键盘隐藏逻辑不变 #if canImport(UIKit) extension View{ func hideKeyboard(){ UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) } } #endif
后续扩展提示
之后需要支持PDF发送时,只需把生成的PDF文件转成Data格式,调用MFMailComposeViewController的addAttachmentData方法添加为附件即可,现有逻辑无需大幅修改。
内容的提问来源于stack exchange,提问作者Omar Mehrez-Kharat
相关产品推荐
相关产品推荐

