SwiftUI로 앱을 개발할 때, UIKit 코드를 사용해야만 하는 경우가 있습니다.
SwiftUI와 UIKit를 혼용하기 위해 세가지 방법들(UIViewRepresentable, UIViewControllerRepresentable, UIHostingController)이 제공됩니다.
UIViewRepresentable은 UIKit View를 SwiftUI View에 통합시켜주기 위해 사용하는 프로토콜입니다.
다른 방법들은 나중에 정리하고, 이번에는 WKWebView(본인인증 연동)를 사용하기 위해 UIViewRepresentable을 사용해보겠습니다.
UIViewRepresentable 프로토콜을 채택하면 다음 두 가지 메소드를 필수적으로 구현해야합니다.
- makeUIView
→ UIView를 생성하는 메소드입니다. 이 메소드가 리턴한 UIView가 SwiftUI View로 통합됩니다.
func makeUIView(context: Context) -> some UIView {
guard let url = URL(string: self.urlToLoad) else { return WKWebView() }
let urlRequest = URLRequest(url: url)
let webView = WKWebView()
webView.navigationDelegate = context.coordinator
webView.configuration.userContentController.add(self.makeCoordinator(), name: "BRIDGE_AUTH_RESULT")
webView.load(urlRequest)
return webView
}
- updateUIView
→ State의 값이 변경되면 호출되는 메소드입니다.
WKWebView의 탐색 결과에 따른 처리를 위해 WKNavigationDelegate를, 본인 인증 결과에 대한 처리를 위해 WKScriptMessageHandler를 Coordinator 패턴으로 구현하였습니다.
최종 코드는 다음과 같습니다.
import Foundation
import WebKit
import SwiftUI
struct AuthenticationWebView: UIViewRepresentable {
var urlToLoad: String
var onSuccess: () -> Void
var onFail: () -> Void
func receivedStringValueFromWebView(value: String) {
if value == "0000" {
onSuccess()
} else {
onFail()
}
}
func makeUIView(context: Context) -> some UIView {
guard let url = URL(string: self.urlToLoad) else { return WKWebView() }
let urlRequest = URLRequest(url: url)
let webView = WKWebView()
webView.navigationDelegate = context.coordinator
webView.configuration.userContentController.add(self.makeCoordinator(), name: "BRIDGE_AUTH_RESULT")
webView.load(urlRequest)
return webView
}
func updateUIView(_ uiView: UIViewType, context: Context) {
//do nothing
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, WKNavigationDelegate {
var parent: AuthenticationWebView
init(_ uiWebView: AuthenticationWebView) {
self.parent = uiWebView
}
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
webView.scrollView.setContentOffset(CGPoint(x: 0, y: 0), animated: false)
return decisionHandler(.allow)
}
//초기 탐색 프로세스 중 에러
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
print(#fileID, #function, #line, error)
}
//탐색 중 에러
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
print(#fileID, #function, #line, error)
}
}
}
extension AuthenticationWebView.Coordinator: WKScriptMessageHandler {
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
//웹으로부터 수신
if message.name == "BRIDGE_AUTH_RESULT" {
parent.receivedStringValueFromWebView(value: (message.body as? String)!)
}
}
}
처음 본인 인증 기능을 구현해야한다고 들었을 때는 괜히 어려울 것 같고 쫄았었는데...
막상 구현해보니, 본인 인증 서비스 업체로부터 제공받는 웹 페이지(JSP 사용)에서 본인인증 절차가 다 이루어졌고, 앱 쪽은 그냥 본인 인증 웹 페이지만 WKWebView로 보여주고 결과를 WKWebView로부터 받는 것만 구현하면 되었습니다.
'iOS > SwiftUI' 카테고리의 다른 글
[SwiftUI] Menu 관련 버그 (0) | 2022.02.14 |
---|---|
[SwiftUI] SwiftUI로 Naver Map iOS SDK 연동하기 (2) | 2022.02.11 |
[SwiftUI] SwiftUI View 캡쳐하기 (UIGraphicsImageRenderer) (0) | 2022.02.11 |
[SwiftUI] SwiftUI View를 UIView로 변환하기 (UIHostingController) (0) | 2022.02.10 |
[SwiftUI] UIViewControllerRepresentable로 ImagePicker (카메라) 사용하기 (0) | 2022.02.10 |