문서 / 그 밖에 / 네이티브 확장

네이티브 확장

MapConductor는 각 지도 SDK의 모든 기능을 감싸지 않습니다. 통일 API에 없는 표현이 필요해졌을 때, 추상화를 버리지 않고 아래로 내려가기 위한 길이 2가지 마련되어 있습니다. 어느 쪽을 써도, 그 화면의 다른 부분은 공통 API인 채로 동작합니다.

1 · HOLDER
Android · iOS · React
2 · REGISTRY
Android · iOS · React

01 · 추상화의 끝

통일 API가 다루는 것은, 어느 프로바이더에도 공통으로 있는 개념뿐입니다. 3D 건물의 돌출, 특정 벤더의 교통량 레이어, 독자적인 셰이더 같은 것은 의도적으로 대상 밖으로 두었습니다. 전부를 감싸려고 하면, 공통 API가 최소공배수가 되어 쓰기 어려워지기 때문입니다.

1 · MapViewHolder

실체를 그대로 빌린다

네이티브 지도 인스턴스를 꺼내, 그 SDK의 API를 직접 호출합니다. 3개 플랫폼 모두에 있습니다.

2 · MapServiceRegistry

기능을 끼워 넣는다

추가 모듈이, Core를 개조하지 않고 자신의 기능을 타입이 붙은 키로 등록합니다. SDK를 확장하는 쪽의 구조입니다.

플랫폼

02 · 네이티브 지도에 손대기

상태 객체에서 getMapViewHolder()를 호출하면, 그 프로바이더의 지도 뷰와 지도 인스턴스를 가진 홀더가 반환됩니다. 타입을 좁히면, 그 다음은 순수한 SDK입니다. 좌표와 화면 픽셀의 상호 변환도 이 홀더가 가지고 있습니다.

멤버
설명
mapView
프로바이더의 뷰(MKMapView・MapView・maplibregl.Map의 컨테이너 등).
map
지도 자체의 인스턴스. SDK의 API는 여기서 호출합니다.
toScreenOffset(position)
좌표를 화면 픽셀로. 기울기나 회전이 반영됩니다.
fromScreenOffset(offset)
화면 픽셀을 좌표로. 비동기 버전과 동기 버전이 있습니다.
Kotlin
// 좁히고 나면 이 지점부터는 전부 순수한 Google Maps SDK
val holder = mapViewState.getMapViewHolder()
if (holder is GoogleMapViewHolder) {
    holder.map.isTrafficEnabled = true
}

홀더는 지도의 초기화가 끝난 뒤에 쓸 수 있습니다. 미초기화 동안은 null이 반환되므로, onMapLoaded 안이나 그 뒤의 조작에서 호출하세요.

03 · 모듈을 끼워 넣기

추가 모듈이, Core를 개조하지 않고 자신의 기능을 끼워 넣기 위한 창구가 MapServiceRegistry입니다. 타입이 붙은 키로 등록하고, 필요한 쪽이 같은 키로 꺼냅니다. 키가 타입을 가지므로, 꺼낸 값의 캐스트는 필요 없습니다. 현재 이것을 쓰고 있는 것은 마커 클러스터링으로, 프로바이더가 등록한 MarkerRenderingSupport를 찾아 렌더링합니다.

Android · React

MapServiceRegistry

MapServiceKey<T>를 싱글턴으로 정의하고, MutableMapServiceRegistry에 put, 이용 측은 get으로 받습니다. Android에서는 CompositionLocal(LocalMapServiceRegistry)에서 지도 스코프의 등록부를 참조합니다.

iOS

MapServiceRegistryScope

키는 MapServiceKey에 준거한 타입으로 정의하고, MutableMapServiceRegistry에 put 합니다. 등록부는 상태 객체(MapViewState.serviceRegistry)가 가지며, 프로바이더는 content를 조립하는 동안에만 MapServiceRegistryScope.with(...)로 그것을 보이게 합니다. SwiftUI의 Environment가 아닌 것은, 지도의 내용이 MapViewContent라는 값이지 뷰 계층이 아니기 때문입니다.

map/MapServiceRegistry · 타입이 붙은 키의 형태
// Kotlin: 키는 singleton object로 정의한다
object MarkerRenderingSupportKey : MapServiceKey<MarkerRenderingSupport<*>>

registry.put(MarkerRenderingSupportKey, support)
val support = registry.get(MarkerRenderingSupportKey) // 타입이 유지된 채로 돌아온다

// Swift: 키는 MapServiceKey를 준수하는 타입으로 정의한다
enum MarkerRenderingSupportKey: MapServiceKey {
    typealias Value = any MarkerRenderingSupport
}

registry.put(MarkerRenderingSupportKey.self, support)
let support = registry.get(MarkerRenderingSupportKey.self)

// TypeScript: 키는 createMapServiceKey<T>()로 만든다
const MarkerRenderingSupportKey = createMapServiceKey<MarkerRenderingSupport>();

여기서 든 3가지는 어느 것이나 프로바이더 고유의 코드를 화면에 들여옵니다. 프로바이더를 교체했을 때 동작하지 않게 되는 부분이므로, 쓴 곳은 분기의 안쪽에 모아 두기를 권합니다.

관련 페이지