SwiftUI 카카오맵 생성 오류

문의 시, 사용하시는 SDK 버전 정보와 디벨로퍼스 앱ID를 알려주세요.


KMSDK] Version : 2.10.5-b4

SwiftUI로 맵 생성하고 있는데, 인증은 성공했다고 나오는데 화면이 연두색으로만 나옵니다…
혹시 원인을 알 수 있을까요?

ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ

[I][KMSDK] [MTLMapContainer(252f7d0)] initializeView

[I][KMSDK] [MTLMapContainer(252f7d0)] Not first run.

[I][KMSDK] ASSET ROOT PATH: /Users/haesik/Library/Developer/CoreSimulator/Devices/9321F071-40B5-485D-8925-A3D264AC5450/data/Containers/Bundle/Application/3F1E1A41-8FD2-4D17-A678-B3747827E6A2/MatJang.app/KakaoMapsSDK-SPM_KakaoMapsSDK-SPM.bundle/assets/

[I][KMSDK] ASSET ROOT PATH:

[I][KMSDK] Version : 2.10.5-b4

[I][K3fCore] app diplay scale: 1.500000

[I][KMSDK] ASSET ROOT PATH: /Users/haesik/Library/Developer/CoreSimulator/Devices/9321F071-40B5-485D-8925-A3D264AC5450/data/Containers/Bundle/Application/3F1E1A41-8FD2-4D17-A678-B3747827E6A2/MatJang.app/KakaoMapsSDK-SPM_KakaoMapsSDK-SPM.bundle/assets/

[I][DiskCache] DiskCache instance count : 1

[I][DiskCache] DB multithreading mode set to SQLITE_CONFIG_SINGLETHREAD

[I][DiskCache] DiskCache check init state…

[I][DiskCache] Dao initialize…

[I][DiskCache] DiskCache db(/Users/haesik/Library/Developer/CoreSimulator/Devices/9321F071-40B5-485D-8925-A3D264AC5450/data/Containers/Data/Application/7C99AAD5-6BD6-479B-9CF1-6BBF083A08BF/Library/Caches/vectormap/cache/db/cache.db) opened.

[I][DiskCache] Buffer initialize lock waiting : 0

[I][DiskCache] Buffer initialize elapsed time : 0, buffer size : 0

[I][DiskCache] DiskCache initialized

[I][K3fCore] DownloadManager initialized

[I][K3fCore] >>> Initialize appEngine[RELEASE]{1721626235}

Optional(“RenderMode : Metal\nDeviceInfo\nDeviceName : iPhone Simulator\nDeviceVersion : 0.0\nOSType : 1\nOSVersion : os:17.5.0\nSDKVersion : 2.10.5-b4\nDocumentPath : /Users/haesik/Library/Developer/CoreSimulator/Devices/9321F071-40B5-485D-8925-A3D264AC5450/data/Containers/Data/Application/7C99AAD5-6BD6-479B-9CF1-6BBF083A08BF/Documents\nViewSize : 3, 3\ndensity : 3, ppi : 200\nAppName : sik.MatJang\n========================\nRenderView Infos\n========================\nEngine state : stopped\n”)

fuction call

[I][K3fCore] >>> Start appEngine[RELEASE]{1721626235}

[I][KMSDK] [MTLMapContainer(6fac2ab8)] StartEngine

[I][Auth] Auth result Received

[I][Auth] Authentication OK!!

[I][K3fCore] Engine{1721626235} stopped.

[I][KMSDK] [MTLMapContainer(6fac2b98)] StopEngine

[I][KMSDK] [MTLMapContainer(252f7d0)] layoutSubviews

[I][KMSDK] [MTLMapContainer(252f7d0)] layoutSubviews

성공

ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ

MatJangApp.swift

import SwiftUI
import KakaoSDKAuth
import KakaoSDKCommon
import KakaoMapsSDK

@main
struct MatJangApp: App {
let kakaoNativeAppKey = Bundle.main.infoDictionary?[“KAKAO_NATIVE_APP_KEY”] as? String ?? “”

init(){
    KakaoSDK.initSDK(appKey: kakaoNativeAppKey)
    SDKInitializer.InitSDK(appKey: kakaoNativeAppKey)
}
var body: some Scene {
    WindowGroup {
        MainMap()

    }
    
}

MainMap.swift

import SwiftUI
import KakaoMapsSDK

struct MainMap: View {
@State var draw: Bool = false

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


func makeUIView(context: Self.Context) -> KMViewContainer {
    let view: KMViewContainer = KMViewContainer()
    view.sizeToFit()
    context.coordinator.createController(view)
    context.coordinator.controller?.prepareEngine()
    


    return view
}

func updateUIView(_ uiView: KMViewContainer, context: Self.Context) {
        if draw {
            context.coordinator.controller?.activateEngine()
        }
        else {
            context.coordinator.controller?.resetEngine()
        }
    }

func makeCoordinator() -> KakaoMapCoordinator {
        return KakaoMapCoordinator()
}

static func dismantleUIView(_ uiView: KMViewContainer, coordinator: KakaoMapCoordinator) {
        
}

class KakaoMapCoordinator: NSObject, MapControllerDelegate{
    override init(){
        first = true
        super.init()
        
        
    }
    
    func authenticationSucceeded() {
            print("성공")
        }
    

    
    func createController(_ view: KMViewContainer) {
        controller = KMController(viewContainer: view)
        controller?.delegate = self
        print(controller?.getStateDescMessage())
        print("fuction call")
    }
    
    func addViews() {
        let defaultPosition: MapPoint = MapPoint(longitude: 14135167.020272, latitude: 4518393.389136)
        let mapviewInfo: MapviewInfo = MapviewInfo(viewName: "mapview", viewInfoName: "map", defaultPosition: defaultPosition)
        
        controller?.addView(mapviewInfo)
    }
    
    func addViewSucceeded(_ viewName: String, viewInfoName: String) {
        print("OK") //추가 성공. 성공시 추가적으로 수행할 작업을 진행한다.
    }
        
            //addView 실패 이벤트 delegate. 실패에 대한 오류 처리를 진행한다.
    func addViewFailed(_ viewName: String, viewInfoName: String) {
        print("Failed")
    }
    
    /// 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: 14135167.020272, latitude: 4518393.389136), zoomLevel: 10, mapView: mapView!)
            mapView?.moveCamera(cameraUpdate)
            first = false
        }
    }
    
    var controller: KMController?
    var first: Bool
}

}

@gotlr98
구체적인 원인까지 확인하기 어렵습니다만 로그상으로는 엔진 시작까지는 정상적으로 되었으나 addView가 수행된 기록이 없습니다. 또한 해당 로그가 마지막일 경우 엔진이 정지되어 더이상 렌더링도 되고 있지 않습니다.

제 코드가 가이드를 그대로 따라 한건데 혹시 문제가 있을만한 부분이 있을까요?

@gotlr98
가이드에 제공된 것은 동작을 위한 전체 코드가 아니라서 복사하셔서 동작을 보장할 수 있는 부분이 아닙니다.
좀 더 구체적인 코드 예시가 필요하신 경우 샘플코드를 참조하시면 도움이 될 수 있으니 확인해 보시면 좋을 것 같습니다.

저도 비슷한 문제를 겪고 있습니다만, 저의 경우에는 makeUIView() 내부 prepareEngine() 함수의 실행 시점을 강제로 늦추니 잘 동작합니다.

func makeUIView(context: Self.Context) -> KMViewContainer {
        let view: KMViewContainer = KMViewContainer()
        view.sizeToFit()
        context.coordinator.createController(view)
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
            context.coordinator.controller?.prepareEngine()
        }
        
        return view
    }

하지만 이렇게 고쳤을 때 왜 동작하는 지는 잘 모르겠습니다. ㅠㅠ

혹시 이유를 알 수 있을까요?
@vectordev

@ej4658
이 코드만으로는 이유를 파악하기 어렵습니다. 샘플코드로 다시 확인해보았으나 다른 문제가 없다면 makeUIView 에서 딜레이없이 prepareEngine 까지 호출하여도 동작하는 것은 가능합니다.
앱의 라이프사이클이나 현재 엔진 상태등을 확인하면서 문제점을 파악하는 것이 필요해 보입니다.

이 과정에서 참고하실 만한 부분은

  1. KMViewContainer의 크기가 0 인 경우 prepareEngine이 실패합니다. prepareEngine 함수의 리턴값이나 KMController의 enginePrepared 속성을 통해 확인할 수 있습니다.
  2. 엔진이 prepared 상태가 아닌 경우 activateEngine을 호출하여도 activate 되지 않습니다.