![]() | ![]() |
---|
import SwiftUI
import KakaoMapsSDK
struct MapView: View {
@State var draw: Bool = true // 뷰의 appear 상태를 전달하기 위한 변수.
init() {
SDKInitializer.InitSDK(appKey: Config.kakaoAppKey)
}
var body: some View {
KakaoMapView(draw: $draw)
.onAppear(perform: {
self.draw = true
})
.onDisappear(perform: {
self.draw = false
})
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
struct KakaoMapView: UIViewRepresentable {
@Binding var draw: Bool
/// UIView를 상속한 KMViewContainer를 생성한다.
/// 뷰 생성과 함께 KMControllerDelegate를 구현한 Coordinator를 생성하고, 엔진을 생성 및 초기화한다.
func makeUIView(context: Self.Context) -> KMViewContainer {
let view: KMViewContainer = KMViewContainer()
view.sizeToFit()
context.coordinator.createController(view)
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
context.coordinator.controller?.prepareEngine()
print("makeUIView - Engine prepared!")
}
return view
}
/// Updates the presented `UIView` (and coordinator) to the latest configuration.
/// draw가 true로 설정되면 엔진을 시작하고 렌더링을 시작한다.
/// draw가 false로 설정되면 렌더링을 멈추고 엔진을 stop한다.
func updateUIView(_ uiView: KMViewContainer, context: Self.Context) {
if draw {
context.coordinator.controller?.activateEngine()
print("updateUIView - Engine activated!")
} else {
context.coordinator.controller?.resetEngine()
}
}
/// Coordinator 생성
func makeCoordinator() -> KakaoMapCoordinator {
return KakaoMapCoordinator()
}
/// Cleans up the presented `UIView` (and coordinator) in anticipation of their removal.
static func dismantleUIView(_ uiView: KMViewContainer, coordinator: KakaoMapCoordinator) {
}
/// Coordinator 구현. KMControllerDelegate를 adopt한다.
class KakaoMapCoordinator: NSObject, MapControllerDelegate {
var controller: KMController?
var first: Bool
override init() {
first = true
super.init()
}
// KMController 객체 생성 및 event delegate 지정
func createController(_ view: KMViewContainer) {
controller = KMController(viewContainer: view)
controller?.delegate = self
}
// KMControllerDelegate Protocol method구현
// 엔진 생성 및 초기화 이후, 렌더링 준비가 완료되면 아래 addViews를 호출한다.
// 원하는 뷰를 생성한다.
func addViews() {
let defaultPosition: MapPoint = MapPoint(longitude: 127.108678, latitude: 37.402001)
let mapviewInfo: MapviewInfo = MapviewInfo(viewName: "mapview", viewInfoName: "map", defaultPosition: defaultPosition)
controller?.addView(mapviewInfo)
}
// addView 성공 이벤트 delegate. 추가적으로 수행할 작업을 진행한다.
func addViewSucceeded(_ viewName: String, viewInfoName: String) {
print("OK") // 추가 성공. 성공시 추가적으로 수행할 작업을 진행한다.
}
// addView 실패 이벤트 delegate. 실패에 대한 오류 처리를 진행한다.
func addViewFailed(_ viewName: String, viewInfoName: String) {
print("Failed")
}
func authenticationSucceeded() {
print("auth succeed!!")
}
func authenticationFailed(_ errorCode: Int, desc: String) {
print("auth failed")
print("error code: \(errorCode)")
print(desc)
// print(controller?.getStateDescMessage())
}
// KMViewContainer 리사이징 될 때 호출.
func containerDidResized(_ size: CGSize) {
let mapView: KakaoMap? = controller?.getView("mapview") as? KakaoMap
mapView?.viewRect = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: size)
if first {
let cameraUpdate: CameraUpdate = CameraUpdate.make(target: MapPoint(longitude: 127.108678, latitude: 37.402001), zoomLevel: 10, mapView: mapView!)
mapView?.moveCamera(cameraUpdate)
first = false
}
}
}
}
1️⃣
엔진 초기상태
→ 인증 시작
→ 엔진 대기
→ 인증 성공
→ 엔진 활성
→ 지도 그리기
순으로 진행됨.2️⃣
기존 코드에서 달라진 부분은 🌟로 표시해두었다.
import SwiftUI
import KakaoMapsSDK
struct MapView: View {
@State var draw: Bool = false // 뷰의 appear 상태를 전달하기 위한 변수.
// 🌟 SDKInitializer는 AppDelegate에서 이미 설정했으므로 중복된 기능 제외
var body: some View {
KakaoMapView(draw: $draw)
.onAppear(perform: {
self.draw = true
})
.onDisappear(perform: { self.draw = false })
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
struct KakaoMapView: UIViewRepresentable {
@Binding var draw: Bool
/// UIView를 상속한 KMViewContainer를 생성한다.
/// 뷰 생성과 함께 KMControllerDelegate를 구현한 Coordinator를 생성하고, 엔진을 생성 및 초기화한다.
func makeUIView(context: Self.Context) -> KMViewContainer {
let view: KMViewContainer = KMViewContainer()
view.sizeToFit()
context.coordinator.createController(view)
// 🌟 prepareEngine 비동기적 처리하지 않으면 맵 보이지 않음.
// 🌟 DispatchQueue.main.asyncAfter(deadline: .now() + 2) 사용해도 되지만 대기시간이 있어 async()보다 뷰가 느리게 뜸
DispatchQueue.main.async() {
context.coordinator.controller?.prepareEngine()
print("makeUIView - Engine prepared!")
}
return view
}
/// Updates the presented `UIView` (and coordinator) to the latest configuration.
/// draw가 true로 설정되면 엔진을 시작하고 렌더링을 시작한다.
/// draw가 false로 설정되면 렌더링을 멈추고 엔진을 stop한다.
func updateUIView(_ uiView: KMViewContainer, context: Self.Context) {
if draw {
context.coordinator.controller?.activateEngine()
print("updateUIView - Engine activated!")
} else {
context.coordinator.controller?.resetEngine()
}
}
/// Coordinator 생성
func makeCoordinator() -> KakaoMapCoordinator {
return KakaoMapCoordinator()
}
/// Cleans up the presented `UIView` (and coordinator) in anticipation of their removal.
static func dismantleUIView(_ uiView: KMViewContainer, coordinator: KakaoMapCoordinator) {
}
/// Coordinator 구현. KMControllerDelegate를 adopt한다.
class KakaoMapCoordinator: NSObject, MapControllerDelegate {
var controller: KMController?
var first: Bool
override init() {
first = true
super.init()
}
// KMController 객체 생성 및 event delegate 지정
func createController(_ view: KMViewContainer) {
controller = KMController(viewContainer: view)
controller?.delegate = self
}
// KMControllerDelegate Protocol method구현
// 엔진 생성 및 초기화 이후, 렌더링 준비가 완료되면 아래 addViews를 호출한다.
// 원하는 뷰를 생성한다.
func addViews() {
let defaultPosition: MapPoint = MapPoint(longitude: 127.108678, latitude: 37.402001)
let mapviewInfo: MapviewInfo = MapviewInfo(viewName: "mapview", viewInfoName: "map", defaultPosition: defaultPosition)
controller?.addView(mapviewInfo)
}
// addView 성공 이벤트 delegate. 추가적으로 수행할 작업을 진행한다.
func addViewSucceeded(_ viewName: String, viewInfoName: String) {
print("OK") // 추가 성공. 성공시 추가적으로 수행할 작업을 진행한다.
}
// addView 실패 이벤트 delegate. 실패에 대한 오류 처리를 진행한다.
func addViewFailed(_ viewName: String, viewInfoName: String) {
print("Failed to add view")
}
func authenticationSucceeded() {
print("auth succeed!!")
print(controller?.isEnginePrepared)
print(controller?.isEngineActive)
// 🌟 인증이 완료되면 엔진을 활성화시킨다.
if let controller = controller,
!controller.isEngineActive {
controller.activateEngine()
}
}
func authenticationFailed(_ errorCode: Int, desc: String) {
print("auth failed")
print("error code: \(errorCode)")
print(desc)
}
// KMViewContainer 리사이징 될 때 호출.
func containerDidResized(_ size: CGSize) {
let mapView: KakaoMap? = controller?.getView("mapview") as? KakaoMap
mapView?.viewRect = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: size)
if first {
let cameraUpdate: CameraUpdate = CameraUpdate.make(target: MapPoint(longitude: 127.108678, latitude: 37.402001), zoomLevel: 10, mapView: mapView!)
mapView?.moveCamera(cameraUpdate)
first = false
}
}
}
}
#Preview {
MapView()
}
며칠을 고생하다가 드디어 지도 안보이는 이슈를 해결했다.
KakaoMapsSDK가 최근에 V2로 바뀜 + 계속 업데이트 되는 중 이슈로 생각보다 자료가 적었는데 해결되어 다행이다.👍