2023. 4. 12. 15:24ㆍiOS/프로젝트
메시지 전송 테스트
음성 메시지를 보낼 방법을 고민하다가, 우선은 복잡하게 하기 보다는 메시지로 파일 전송할 수 있도록 하는 것이 좋을 것 같았습니다. 그래서 목표는 메시지를 전송할 수 있도록 테스트 하는 것입니다.
목표 달성
MessageUI
우선 문서를 살펴 보니 메시지 관련 두 프레임워크가 존재했습니다. Messages
, MessageUI
였습니다. 살펴본 결과 앱에서 메시지를 전송하는 화면을 띄워야 하기 때문에 MessageUI
를 사용하는 것이 적합하는 결론을 내렸습니다.
그 과정에서 아래의 블로그가 아주 큰 도움이 되었습니다!
https://medium.com/@DevVenusK/swift-를-이용해-sms-를-보내보자-34555582f84c
Swift 를 이용해 SMS 를 보내보자
영화를 예매하거나, 공연을 예매할 때 우리는 예매내역을 문자로 전송을 할 수 있어요.
medium.com
SwiftUI에서 ViewController 사용하기
원하는 목표를 이루기 위해 사용자가 SMS/MMS 메시지를 구성하고 전송할 수 있도록 도와주는 뷰 컨트롤러인 MFMessageComposeViewController
를 써야 했습니다.
그래서 아래의 아주 친절한 블로그를 참고하였습니다.
https://sarunw.com/posts/uiviewcontroller-in-swiftui/
How to use UIViewController in SwiftUI | Sarunw
Learn how to use UIViewController as a SwiftUI view.
sarunw.com
struct MessageUIView: UIViewControllerRepresentable {
typealias UIViewControllerType = MFMessageComposeViewController
/// 뷰 컨트롤러의 인스턴스를 반환한다
func makeUIViewController(context: Context) -> MFMessageComposeViewController {
let vc = MFMessageComposeViewController()
vc.recipients = ["123456789"] // 메시지를 받을 사람
vc.body = "음성 메시지를 보내고 싶어요" // 메시지 내용
return vc
}
/// SwiftUI 뷰의 정보로 뷰 컨트롤러의 상태를 업데이트한다
func updateUIViewController(_ uiViewController: MFMessageComposeViewController, context: Context) {
}
}
SwiftUI에서 뷰 컨트롤러를 사용하기 위해서 UIViewControllerRepresentable
이라는, UIKit의 view controller를 SwiftUI 뷰로 대응시킬 수 있게 하는 프로토콜을 사용합니다.
- 어떤
ViewController
를 사용할 건지 타입 명시합니다. - 필수 함수들을 구현합니다.
makeUIViewController
함수는 뷰 컨트롤러의 인스턴스를 반환합니다. 이 함수 내에서 필요한 설정을 할 수 있는데, 저는 메시지 수령 정보와 텍스트 내용을 넣어 주었습니다.updateUIViewController
는 SwiftUI 뷰의 정보로 뷰 컨트롤러의 상태를 업데이트합니다. 저는 딱히 필요하지 않은 것 같아 스킵하였습니다.
SwiftUI에서 delegate 사용하기
메시지 화면은 잘 떴는데, 취소 버튼을 눌러도 아무 반응이 없더라구요! 그래서 취소 / 전송 성공 / 오류 등등의 처리를 하기 위한 MFMessageComposeViewControllerDelegate
를 사용해야 했습니다.
아 그리고 SwiftUI에서 모달을 닫기 위해서 UIKit에서 사용되는 dismiss 대신 전달받은 isPresented
값을 바꾸는 방식을 사용하였습니다.
struct MessageUIView: UIViewControllerRepresentable {
@Binding var isPresented: Bool
// ...
typealias Coordinator = MessageCoordinator
func makeUIViewController(context: Context) -> MFMessageComposeViewController {
// ...
vc.messageComposeDelegate = context.coordinator
return vc
}
// ...
/// makeCoordinator(): 뷰 컨트롤러의 변화를 SwiftUI에 알리기 위해 사용하는 커스텀 인스턴스
func makeCoordinator() -> Coordinator {
return MessageCoordinator(self)
}
}
@Binding
값으로 모달이 보여질지 여부를 나타내는isPresented
변수를 받습니다makeUIViewController
에서 뷰 컨트롤러를 설정할 때,messageComposeDelegate
을context
의coordinator
로 설정합니다.- 뷰 컨트롤러의 변화를 SwiftUI에 알리기 위해 사용하는 커스텀 인스턴스인
makeCoordinator()
는 우리가 불러줄 필요 없이 자동으로 호출이 되며 따라서 위에서context.coordiantor
로 접근할 수 있게 됩니다.
이제 실제 Coordinator
를 구현합니다.
/// 메시지 전송 처리를 하기 위한 Coordinator
class MessageCoordinator: NSObject, MFMessageComposeViewControllerDelegate {
var parent: MessageUIView
init(_ parent: MessageUIView) {
self.parent = parent
}
// TODO: 메시지 전송 처리
func messageComposeViewController(_ controller: MFMessageComposeViewController, didFinishWith result: MessageComposeResult) {
switch result {
case .cancelled:
print("cancelled")
parent.isPresented = false
case .sent:
print("sent message:", controller.body ?? "")
parent.isPresented = false
case .failed:
print("failed")
parent.isPresented = false
@unknown default:
print("unkown Error")
parent.isPresented = false
}
}
}
parent
로MessageUIView
를 받습니다. 이는parent
의isPresent
값에 접근하기 위함입니다.messageComposeViewController
의result
값에 따라 알맞은 처리를 해줍니다. 우선은 어떤 경우든 다 모달을 닫도록 구현했습니다.
실제 메시지 화면 띄워보기
import SwiftUI
import MessageUI
struct TestMessageView: View {
@State var isPresented = false
var body: some View {
Button("메시지를 보내고 싶다") {
/// canSendText: 지금 디바이스가 메시지를 보낼 수 있는 상태인지 Bool 값 리턴
guard MFMessageComposeViewController.canSendText() else {
print("메시지를 보낼 수 없습니다.")
return
}
isPresented = true
}
.sheet(isPresented: $isPresented) {
MessageUIView(isPresented: $isPresented)
}
}
}
isPresented
값을 선언하고MessageUIView
에 Binding으로 넘겨줍니다. 그리고 그 값에 따라 모달이 닫힘 / 열림이 결정됩니다.- 메시지를 보내기 전에
MFMessageComposeViewController.canSendText
를 통해 메시지를 보낼 수 있는 상태인지 확인해야 합니다.- 만약 메시지를 보낼 수 없는 경우엔
MFMessageComposeViewControllerTextMessageAvailabilityDidChange
notification의 옵저버를 등록해서 메시지를 보낼 수 있는 상태로 변할 때 알 수 있다고 합니다. 그런데 Notification은 아직 익숙치 않아 나중에 해 봐야겠습니다..
- 만약 메시지를 보낼 수 없는 경우엔
- 버튼을 누르면 메시지 수령 번호와 텍스트가 적힌 아까 설정한
MFMessageComposeViewController
, 즉MessageUIView
가 화면에 띄워집니다.
결과 화면

아! 참고로 MessageUI
는 시뮬레이터로는 확인이 되지 않습니다. 꼭 실제 기기로 확인하세요.
남아있는 질문들
- 사용하지 않은
updateUIViewController
의 역할이 정확히 무엇인지? - 메시지 전송 결과를 제대로 처리하는 법?
- Notification을 통해 메시지 전송 가능 상태를 아는 법?
대답한 질문들
없습니다.. 반성해야겠습니다. 한번 날을 잡아서 대답 못한 질문들을 대답해야겠네요.
'iOS > 프로젝트' 카테고리의 다른 글
개인프로젝트 - 5 (SwiftLint) (0) | 2023.04.17 |
---|---|
개인 프로젝트 기록 - 3 (CoreData) (0) | 2023.04.01 |
개인 프로젝트 기록 - 2 (Recording) (0) | 2023.04.01 |
개인 프로젝트 기록 - 1 (Ear Speaker) (0) | 2023.04.01 |
개인 프로젝트 기록 - 0 (시작) (0) | 2023.04.01 |