반응형
[Swift/ TIL #36] 2023 / 07 / 11
이전에 이미 메일 보내는 기능을 구현을 해봤었는데,
오랜만에 다시 구현하려니 헷갈려서 간단히 정리한 뒤, 다시 사용하려고 이렇게 정리합니다.
사용방법은 공식문서 에 자세히 설명이 돼있어요.
시작
이렇게 버튼을 만들어줬고 버튼을 클릭하면 mail을 보내는 기능을 만들어 보려합니다.
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 기능을 사용하기 위해 프레임워크를 추가해 줍니다.
import MessageUI
다음으로 사용자 디바이스에서 email 기능이 활성화돼 있는지 여부를 확인해줘야 합니다.
만약, email이 비활성화돼 있을 경우는 사용자에게 따로 알려줘야겠죠!
if MFMailComposeViewController.canSendMail() {
// 메일 작성 화면 설정
} else {
// 만약, 디바이스에 email 기능이 비활성화 일 때, 사용자에게 알림
}
들어가기 전, 메일 작성 화면이 어떻게 구성돼 있나, 그림과 같이 살펴봅시다.
메일 작성 화면의 구성
Recipients: 받는 사람의 메일 주소
Subject: 제목
MessageBody: 본문 내용
위의 작성 화면 규격대로 만들어봅시다.
@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
}
// 자동으로 dismiss가 되지 않으므로, 작업 완료 시 dismiss를 해줘야 함
self.dismiss(animated: true)
}
}
전체 코드
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
}
// 디바이스 모델 찾기
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
}
}
}
참고, HTML으로 본문 생성
@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)
}
}
반응형
'프로젝트' 카테고리의 다른 글
[Swift/ TIL #37] UIPageViewController를 사용하여 튜토리얼 화면을 만들기 (0) | 2023.07.18 |
---|---|
[Swift/ TIL #36] Web 보여주기 (Safari 앱, SFSafariViewController, WKWebView) (0) | 2023.07.12 |
[Swift/ TIL #34] enum에서 Protocol 채택 및 적용 (프로토콜의 요구사항을 열거형 case에 적용) (0) | 2023.07.06 |
[Swift/ TIL #33] Git 커밋 메시지 컨벤션(+Gitmoji) (0) | 2023.06.29 |
[Swift/ TIL #32] 탭바 선택 시, 뷰컨이 나타나는 애니메이션 효과를 넣어보자 (0) | 2023.06.27 |