Danny의 iOS 컨닝페이퍼
article thumbnail
반응형

1. [Swift/ TIL #36] 2023 / 07 / 11

이전에 이미 메일 보내는 기능을 구현을 해봤었는데,

오랜만에 다시 구현하려니 헷갈려서 간단히 정리한 뒤, 다시 사용하려고 이렇게 정리합니다.

 

사용방법은 공식문서 에 자세히 설명이 돼있어요.

 

 

2. 시작

이렇게 버튼을 만들어줬고 버튼을 클릭하면 mail을 보내는 기능을 만들어 보려합니다.

<swift>
class ViewController: UIViewController { lazy var button: UIButton = { let button = UIButton(configuration: .filled()) button.frame = CGRect(x: 150, y: 400, width: 100, height: 50) button.setTitle("문의 사항", for: .normal) button.addTarget(self, action: #selector(buttonHandler), for: .touchUpInside) return button }() override func viewDidLoad() { super.viewDidLoad() view.addSubview(button) } @objc func buttonHandler(_ sender: UIButton) { } }

 

가장 처음으로 Mail 기능을 사용하기 위해 프레임워크를 추가해 줍니다.

<swift>
import MessageUI

 

다음으로 사용자 디바이스에서 email 기능이 활성화돼 있는지 여부를 확인해줘야 합니다.

만약, email이 비활성화돼 있을 경우는 사용자에게 따로 알려줘야겠죠!

<swift>
if MFMailComposeViewController.canSendMail() { // 메일 작성 화면 설정 } else { // 만약, 디바이스에 email 기능이 비활성화 일 때, 사용자에게 알림 }

 

들어가기 전, 메일 작성 화면이 어떻게 구성돼 있나, 그림과 같이 살펴봅시다.

 

메일 작성 화면의 구성

Recipients: 받는 사람의 메일 주소

Subject: 제목

MessageBody: 본문 내용

 

위의 작성 화면 규격대로 만들어봅시다.

<swift>
@objc func buttonHandler(_ sender: UIButton) { if MFMailComposeViewController.canSendMail() { let composeVC = MFMailComposeViewController() composeVC.mailComposeDelegate = self let bodyString = """ 이곳에 내용을 작성해 주세요. ================================ Device Model : \(UIDevice.current.modelName) Device OS : \(UIDevice.current.systemVersion) App Version : \(currentAppVersion) ================================ """ // 받는 사람 이메일, 제목, 본문 composeVC.setToRecipients(["scarlet040@gmail.com"]) composeVC.setSubject("문의 사항") composeVC.setMessageBody(bodyString, isHTML: false) self.present(composeVC, animated: true) } else { // 만약, 디바이스에 email 기능이 비활성화 일 때, 사용자에게 알림 let alertController = UIAlertController(title: "메일 계정 활성화 필요", message: "Mail 앱에서 사용자의 Email을 계정을 설정해 주세요.", preferredStyle: .alert) let alertAction = UIAlertAction(title: "확인", style: .default) { _ in guard let mailSettingsURL = URL(string: UIApplication.openSettingsURLString + "&&path=MAIL") else { return } if UIApplication.shared.canOpenURL(mailSettingsURL) { UIApplication.shared.open(mailSettingsURL, options: [:], completionHandler: nil) } } alertController.addAction(alertAction) self.present(alertController, animated: true) } }

 

델리게이트 메서드를 통해 각 분기마다 추가 설정도 가능합니다.

<swift>
extension ViewController: MFMailComposeViewControllerDelegate { // 메일 작성이 끝났을 때, 호출되는 메서드 func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) { switch result { case .sent: print("메일 보내기 성공") case .cancelled: print("메일 보내기 취소") case .saved: print("메일 임시 저장") case .failed: print("메일 발송 실패") @unknown default: break } // 자동으로 dismiss가 되지 않으므로, 작업 완료 시 dismiss를 해줘야 함 self.dismiss(animated: true) } }

 

 

전체 코드

<swift>
import UIKit import MessageUI class ViewController: UIViewController { lazy var button: UIButton = { let button = UIButton(configuration: .filled()) button.frame = CGRect(x: 150, y: 400, width: 100, height: 50) button.setTitle("문의 사항", for: .normal) button.addTarget(self, action: #selector(buttonHandler), for: .touchUpInside) return button }() override func viewDidLoad() { super.viewDidLoad() view.addSubview(button) } @objc func buttonHandler(_ sender: UIButton) { if MFMailComposeViewController.canSendMail() { let composeVC = MFMailComposeViewController() composeVC.mailComposeDelegate = self let bodyString = """ 이곳에 내용을 작성해 주세요. ================================ Device Model : \(UIDevice.current.modelName) Device OS : \(UIDevice.current.systemVersion) App Version : \(currentAppVersion) ================================ """ composeVC.setToRecipients(["scarlet040@gmail.com"]) composeVC.setSubject("문의 사항") composeVC.setMessageBody(bodyString, isHTML: false) self.present(composeVC, animated: true) } else { // 만약, 디바이스에 email 기능이 비활성화 일 때, 사용자에게 알림 let alertController = UIAlertController(title: "메일 계정 활성화 필요", message: "Mail 앱에서 사용자의 Email을 계정을 설정해 주세요.", preferredStyle: .alert) let alertAction = UIAlertAction(title: "확인", style: .default) { _ in guard let mailSettingsURL = URL(string: UIApplication.openSettingsURLString + "&&path=MAIL") else { return } if UIApplication.shared.canOpenURL(mailSettingsURL) { UIApplication.shared.open(mailSettingsURL, options: [:], completionHandler: nil) } } alertController.addAction(alertAction) self.present(alertController, animated: true) } } } extension ViewController: MFMailComposeViewControllerDelegate { func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) { switch result { case .sent: print("메일 보내기 성공") case .cancelled: print("메일 보내기 취소") case .saved: print("메일 임시 저장") case .failed: print("메일 발송 실패") @unknown default: break } self.dismiss(animated: true) } } // 현재 앱 버전 가져오기 fileprivate var currentAppVersion: String { guard let dictionary = Bundle.main.infoDictionary, let version = dictionary["CFBundleShortVersionString"] as? String else { return "" } return version }
<swift>
// 디바이스 모델 찾기 extension UIDevice { var modelName: String { var systemInfo = utsname() uname(&systemInfo) let machineMirror = Mirror(reflecting: systemInfo.machine) let identifier = machineMirror.children.reduce("") { identifier, element in guard let value = element.value as? Int8, value != 0 else { return identifier } return identifier + String(UnicodeScalar(UInt8(value))) } switch identifier { case "i386", "x86_64": return "Simulator" case "iPhone1,1": return "iPhone" case "iPhone1,2": return "iPhone 3G" case "iPhone2,1": return "iPhone 3GS" case "iPhone3,1", "iPhone3,2", "iPhone3,3": return "iPhone 4" case "iPhone4,1": return "iPhone 4S" case "iPhone5,1", "iPhone5,2": return "iPhone 5" case "iPhone5,3", "iPhone5,4": return "iPhone 5C" case "iPhone6,1", "iPhone6,2": return "iPhone 5S" case "iPhone7,1": return "iPhone 6 Plus" case "iPhone7,2": return "iPhone 6" case "iPhone8,1": return "iPhone 6s" case "iPhone8,2": return "iPhone 6s Plus" case "iPhone8,4": return "iPhone SE" case "iPhone9,1", "iPhone9,3": return "iPhone 7" case "iPhone9,2", "iPhone9,4": return "iPhone 7 Plus" case "iPhone10,1", "iPhone10,4": return "iPhone 8" case "iPhone10,2", "iPhone10,5": return "iPhone 8 Plus" case "iPhone10,3", "iPhone10,6": return "iPhone X" case "iPhone11,2": return "iPhone XS" case "iPhone11,4", "iPhone11,6": return "iPhone XS Max" case "iPhone11,8": return "iPhone XR" case "iPhone12,1": return "iPhone 11" case "iPhone12,3": return "iPhone 11 Pro" case "iPhone12,5": return "iPhone 11 Pro Max" case "iPhone12,8": return "iPhone SE (2nd generation)" case "iPhone13,1": return "iPhone 12 mini" case "iPhone13,2": return "iPhone 12" case "iPhone13,3": return "iPhone 12 Pro" case "iPhone13,4": return "iPhone 12 Pro Max" default: return identifier } } }

 

 

3. 참고, HTML으로 본문 생성

<swift>
@objc func buttonHandler(_ sender: UIButton) { if MFMailComposeViewController.canSendMail() { let composeVC = MFMailComposeViewController() composeVC.mailComposeDelegate = self let bodyString = """ <html> <body> <h1>내용을 작성해 주세요.</h1><br> <p>================================ Device Model : \(UIDevice.current.modelName)<br> Device OS : \(UIDevice.current.systemVersion)<br> App Version : \(currentAppVersion)<br> ===============================</p> </body> </html> """ composeVC.setToRecipients(["scarlet040@gmail.com"]) composeVC.setSubject("문의 사항") // 👉 본문 내용을 HTML로 작성 후, isHTML을 true로 변경 composeVC.setMessageBody(bodyString, isHTML: true) self.present(composeVC, animated: true) } }

 

 

반응형
profile

Danny의 iOS 컨닝페이퍼

@Danny's iOS

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!