SwiftUI를 사용해서 다음 우편번호 검색 페이지를 구현하려고 합니다.
제가 구현할 범위는
https://postcode.map.daum.net/guide
위 링크는 공식문서입니다!
공식문서가 있지만 저는 공식문서대로 진행하면 계속 오류가 발생하더라고요
그래서 다른 분들의 블로그를 보면서 구현해봤습니다.
우편번호 서비스 문서를 보면 스크립트나, html로 구현되어있습니다.
구현하는 방식이 클라이언트에 추가하는 방식이 아니라
으로 구현해야합니다.
그래서 저는 깃페이지를 사용해 우편번호검색 페이지를 만들었습니다! (깃을 사용한 웹사이트가 아니여도 웹사이트 만들듯이 하나 만들면 됩니다!)
일단 퍼블릭 레포를 하나 생성하고
Setting 메뉴 -> 카테고리 Pages를 선택해서 들어가면
Source 창에 브랜치를 선택하는 부분이 있습니다.
거기서
main root save
에 save 버튼을 선택하면 주소가 나옵니다.
그 주소가 바로 저희가 우편번호검색 페이지를 사용할 웹페이지 주소가 됩니다.
바로 main 브랜치에 add file -> create new file을 선택합니다.
그리고 index.html로 이름을 설정해준 뒤
<html lang="ko">
<head>
<title>주소 찾기</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,height=device-height,initial-scale=1.0"/>
</head>
<body onload="execDaumPostcode()">
<div id = "layer" style = "display:block; position:absolute; overflow:hidden; z-index:1; -webkit-overflow-scrolling:touch; ">
</div>
<script src="https://spi.maps.daum.net/imap/map_js_init/postcode.v2.js"></script>
<script>
window.addEventListener("message", onReceivedPostMessage, false);
function postMessageToiOS(postData) {
window.webkit.messageHandlers.callBackHandler.postMessage(postData);
}
var element_layer = document.getElementById('layer');
function execDaumPostcode() {
new daum.Postcode({
oncomplete: function(data) {
var jibunAddress = ""
if (data.jibunAddress == "") {
jibunAddress = data.autoJibunAddress
} else if (data.autoJibunAddress == "") {
jibunAddress = data.jibunAddress
}
var postData = {
roadAddress : data.roadAddress,
jibunAddress : jibunAddress,
zonecode : data.zonecode
};
window.postMessageToiOS(postData);
},
width : '100%',
height : '100%'
}).embed(element_layer);
element_layer.style.display = 'block';
initLayerPosition();
}
function initLayerPosition(){
var width = (window.innerWidth || document.documentElement.clientWidth);
var height = (window.innerHeight || document.documentElement.clientHeight);
element_layer.style.width = width + 'px';
element_layer.style.height = height + 'px';
element_layer.style.left = (((window.innerWidth || document.documentElement.clientWidth) - width)/2) + 'px';
element_layer.style.top = (((window.innerHeight || document.documentElement.clientHeight) - height)/2) + 'px';
}
</script>
</body>
</html>
위 코드를 작성한 뒤에 적용시키고 깃 페이지 주소로 들어가면

위 사진처럼 다음 우편번호검색 페이지가 만들어졌어요!!
검색페이지를 만들었으니 이제 WebView로 가져와서 사용해야겠죠?
SwiftUI로 사용하려면 UIViewRepresentable을 사용해서 구현해야해요!!
import SwiftUI
import WebKit
struct KakaoPostCodeView: UIViewRepresentable {
let request: URLRequest
var webView: WKWebView?
@Binding var isShowingKakaoWebSheet: Bool
@Binding var address: String
init(
request: URLRequest,
isShowingKakaoWebSheet: Binding<Bool>,
address: Binding<String>
) {
self.webView = WKWebView()
self.request = request
self._isShowingKakaoWebSheet = isShowingKakaoWebSheet
self._address = address
self.webView?.configuration.userContentController.add(KakaoWebController(isShowingkakaoWebSheet: _isShowingKakaoWebSheet, address: _address), name: "callBackHandler")
}
func makeUIView(context: Context) -> WKWebView {
return webView!
}
func updateUIView(_ uiView: WKWebView, context: Context) {
uiView.load(request)
}
func makeCoordinator() -> Coordinator {
Coordinator(parent: self)
}
class Coordinator: NSObject, WKNavigationDelegate {
let parent: KakaoPostCodeView
init(parent: KakaoPostCodeView) {
self.parent = parent
}
}
}
class KakaoWebController: NSObject, WKScriptMessageHandler {
@Binding var isShowingKakaoWebSheet: Bool
@Binding var address: String
init(
isShowingkakaoWebSheet: Binding<Bool>,
address: Binding<String>
) {
self._isShowingKakaoWebSheet = isShowingkakaoWebSheet
self._address = address
}
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
if message.name == "callBackHandler", let data = message.body as? [String: Any] {
if message.name == "callBackHandler" {
print("message name : \(message.name)")
print("post Message : \(message.body)")
if let roadAddress = (data["roadAddress"]) as? String {
print("roadAddress: \(roadAddress)")
address = roadAddress
print(address)
}
isShowingKakaoWebSheet.toggle()
}
}
}
}
extension KakaoPostCodeView {
func callJS(_ args: Any = "") {
webView?.evaluateJavaScript("postMessageToiOS('\(args)')") { result, error in
if let error {
print("Error \(error.localizedDescription)")
return
}
if result == nil {
print("It's void function")
return
}
print("Received Data \(result ?? "")")
}
}
}
위 코드가 제가 구현한 코드입니다.
저는 Binding으로 isShowingKakaoWebSheet와 address를 추가했는데요!!
isShowingKakaoWebSheet는 사용자가 검색 후 주소를 선택하면 바로 sheet가 닫히도록 구현하기 위해 추가했고,
address는 사용자가 주소를 선택하면 바로 TextField에 적용 될 수 있게 하려고 추가했습니다.
위 코드들은 다 우편번호 페이지를 불러오기 위한 코드들이이에요!!
import SwiftUI
struct ContentView: View {
@State var isShowingKakaoWebSheet: Bool = false
@State var address: String = ""
let webURL: URL? = URL(string: "https://uuuunseo.github.io/DaumWeb/")
var body: some View {
VStack {
Button {
isShowingKakaoWebSheet = true
} label: {
Text("주소는 : \(address)")
}
}
.sheet(isPresented: $isShowingKakaoWebSheet) {
if let url = webURL {
KakaoPostCodeView(
request: URLRequest(url: url),
isShowingKakaoWebSheet: $isShowingKakaoWebSheet,
address: $address
)
}
}
}
}
이제 페이지를 구현했으니 원하는 페이지에 sheet를 사용해서 추가만 하면 완성입니다!
KakaoPostCodeView에 보낼 isShowingKakaoWebSheet와 address를 선언하고 깃 페이지 URL을 페이지에 넘겨주기만 하면 완성입니다.
처음에는 이걸 어떻게 구현하지 싶었는데 일단 시작해보고 나니 쉽게 구현할 수 있었던...
코드는 여기서 확인 하실 수 있어요!!!!!
https://github.com/uuuunseo/Studyyy/tree/main/DaumSearchPostCode