[SwiftUI] SwiftUI로 다음 우편번호검색 페이지 구현하기

온오·2024년 8월 22일
post-thumbnail

구현 범위

SwiftUI를 사용해서 다음 우편번호 검색 페이지를 구현하려고 합니다.

제가 구현할 범위는

  1. 버튼 선택 시 우편번호 검색 Sheet가 올라오도록 구현
  2. 우편번호 선택 후 Sheet가 내려가면서 Button에 선택한 주소가 넘어오도록 구현

공식문서

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>

위 코드를 작성한 뒤에 적용시키고 깃 페이지 주소로 들어가면


위 사진처럼 다음 우편번호검색 페이지가 만들어졌어요!!

WebKit 사용해서 페이지 구현하기

검색페이지를 만들었으니 이제 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

구현 영상

참고한 블로그

https://nsios.tistory.com/158
https://da-ye.tistory.com/221

0개의 댓글