만약 Capacitor Google Maps 대안이 필요하다면, 현실적인 세 가지 방법이 있습니다: 공식 @capacitor/google-maps 플러그인을 그대로 유지하고 한계를 우회하거나, MapLibre GL JS나 Leaflet 같은 JavaScript 라이브러리로 WebView 안에 지도를 렌더링하거나, 다른 SDK 기반으로 만든 네이티브 지도 플러그인을 사용하는 것입니다. Capgo은 자체 지도 렌더링 플러그인을 제공하지 않으므로, 이 가이드에서는 각 옵션을 중립적으로 비교하고 어떤 지도와도 잘 작동하는 Capgo 플러그인(내비게이션 핸드오프, 지오코딩, 백그라운드 위치)을 소개합니다.
개발자들이 @capacitor/google-maps을 넘어 대안을 찾는 이유
공식 플러그인(Capacitor 8용 버전 8)은 iOS와 Android에서는 네이티브 Google Maps SDK을, 웹에서는 Google Maps JavaScript API를 임베드합니다. 동작은 하지만, 이런 점들이 계속 문제로 떠오릅니다.
모든 플랫폼에서 결제가 활성화된 Google Cloud 계정 필요
이 플러그인을 Android, iOS, 웹에서 사용하려면 결제가 활성화된 Google Cloud 계정과 연결된 API 키가 필요합니다. 네이티브 모바일 지도 로드에 대한 Google의 가격은 관대한 편이지만, 여전히 결제 수단을 설정하고 플랫폼별로 키를 제한하며 할당량을 모니터링해야 합니다. 웹 지도 로드와 Places, Directions 같은 서비스는 무료 한도 초과 시 사용량에 따라 과금됩니다. 2025년에 과금 모델이 바뀌었으니, 도입 전에 Google Maps Platform의 최신 가격 페이지를 확인하세요.
Android에서는 지도가 WebView 뒤에 그려짐
iOS에서는 지도 뷰가 WebView의 스크롤 뷰 안에 배치됩니다. Android에서는 전체 WebView 아래에 렌더링되며, 플러그인이 해당 <capacitor-google-map> 요소를 따라 지도를 이동시킵니다. 그 위의 모든 레이어는 투명해야 합니다:
/* Required on Android with @capacitor/google-maps */
html,
body,
ion-content,
ion-content::part(background) {
background: transparent !important;
--background: transparent;
}
이것이 “지도가 빈 화면으로 나온다”는 가장 흔한 문제입니다. 또한 HTML이 네이티브 뷰 위에 놓이기 때문에 커스텀 오버레이, 모달, 페이지 전환 구현이 더 어려워집니다.
마커 추가 및 삭제는 가능하지만 업데이트는 불가
API에는 addMarker, addMarkers, removeMarker 및 removeMarkers, 하지만 없습니다 updateMarker. 실시간 차량 위치는 업데이트 시마다 remove와 add를 반복해야 하며, 이로 인해 깜빡임이 발생하고 브리지 호출 비용이 증가합니다.
네이티브에서 스타일링과 기능이 제한적
일부 옵션은 웹 전용입니다. 예를 들어 mapId 클라우드 기반 스타일링을 위해, 그리고 region 및 language. 마커, 클러스터링, 폴리라인, 폴리곤, 원, 타일 오버레이, 카메라 제어 및 클릭 리스너를 제공합니다. 모든 플랫폼에서 동일한 방식으로 데이터 기반 스타일링, 히트맵 또는 3D 건물을 필요로 한다면 한계에 부딪히게 됩니다.
옵션 한눈에 보기
| 옵션 | 렌더링 | API 키 필요 | 타일 소스 | 추천 대상 |
|---|---|---|---|---|
@capacitor/google-maps |
네이티브 SDK(Android, iOS), 웹에서는 JS | 예, 결제 활성화됨 | Google 데이터와 네이티브 성능을 원하는 앱 | |
| MapLibre GL JS | WebView에서 WebGL | 타일 제공업체에 따라 다름 | 모든 벡터 타일 소스 지원, 자체 호스팅 가능 | 커스텀 스타일 지도, 오프라인에 가까움, 벤더 종속 없음 |
| Leaflet | WebView에서 DOM 및 canvas | 타일 제공업체에 따라 다름 | 래스터 타일 (OSM 기반 또는 기타) | 간단한 맵, 작은 번들, 다양한 플러그인 |
| WebView에서 Google Maps JS API | Google의 JS 렌더러 | 지원 | 모든 플랫폼에서 동일한 Google 스타일, 전체 JS 기능 세트 | |
| 네이티브 MapLibre 또는 Mapbox 플러그인 | 네이티브 SDK | 상황에 따라 다름 | 모두 / Mapbox | 대용량 데이터, 장시간 세션, 네이티브 제스처 |
정답은 하나가 아닙니다. 데이터 양, 스타일링 요구사항, 특정 벤더에 얼마나 의존할지에 따라 선택이 달라집니다.
옵션 1: WebView에서 MapLibre GL JS 사용
MapLibre GL JS는 Mapbox GL JS v1의 오픈소스 포크입니다. WebGL로 벡터 타일을 렌더링하며 WKWebView와 Android System WebView에서 잘 동작합니다. Google의 데이터가 필요하지 않다면 가장 유연한 선택지입니다.
bun add maplibre-gl
import maplibregl from 'maplibre-gl';
import 'maplibre-gl/dist/maplibre-gl.css';
const map = new maplibregl.Map({
container: 'map',
style: 'https://your-tile-provider.example.com/styles/streets/style.json',
center: [2.3522, 48.8566], // [lng, lat]
zoom: 12,
});
map.addControl(new maplibregl.NavigationControl(), 'top-right');
// A marker you can move without remove/add
const courier = new maplibregl.Marker({ color: '#1d4ed8' })
.setLngLat([2.35, 48.85])
.addTo(map);
export function moveCourier(lng: number, lat: number) {
courier.setLngLat([lng, lat]);
}
GeoJSON 레이어, 데이터 기반 스타일링, 경로 라인은 기본으로 지원됩니다:
map.on('load', () => {
map.addSource('route', {
type: 'geojson',
data: {
type: 'Feature',
properties: {},
geometry: {
type: 'LineString',
coordinates: [
[2.3522, 48.8566],
[2.3376, 48.8606],
[2.2945, 48.8584],
],
},
},
});
map.addLayer({
id: 'route-line',
type: 'line',
source: 'route',
paint: { 'line-color': '#2563eb', 'line-width': 5 },
});
});
알아둘 점:
- 타일 소스가 필요합니다. 상용 벡터 타일 호스트를 사용하거나 OpenStreetMap 데이터로 생성한 타일을 직접 호스팅할 수 있습니다. OpenStreetMap 공용 타일 서버의 사용 정책은 과도한 앱 트래픽을 허용하지 않습니다.
- 타일 제공업체가 요구하는 출처 표시를 항상 보여주세요.
- 일반 웹 code이므로 브라우저 미리보기에서도 같은 지도가 동작해 개발 속도가 빨라집니다.
옵션 2: Leaflet 사용
Leaflet은 가볍고 안정적입니다. 수백 개의 마커, 래스터 타일, 간단한 인터랙션이 필요한 지도에 적합합니다.
bun add leaflet
import L from 'leaflet';
import 'leaflet/dist/leaflet.css';
const map = L.map('map').setView([48.8566, 2.3522], 13);
L.tileLayer('https://tiles.example.com/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '© OpenStreetMap contributors',
}).addTo(map);
L.marker([48.8584, 2.2945]).addTo(map).bindPopup('Eiffel Tower');
번들링된 앱에서는 Leaflet의 기본 마커 아이콘 경로가 자주 깨집니다. 아이콘 이미지를 import한 다음 L.Icon.Default 옵션을 설정하거나 직접 만든 아이콘을 사용하세요. L.divIcon.
옵션 3: WebView에서 Google Maps JavaScript API 사용
Google의 데이터와 디자인은 유지하면서 지도를 일반 HTML 요소처럼 동작하게 하고 싶다면, 네이티브 SDK 대신 WebView에서 Maps JavaScript API를 로드하세요. 네이티브 특유의 부드러움은 다소 줄고 지도 로드마다 과금되는 웹 로드가 발생하지만, Map ID를 활용한 클라우드 스타일링, 고급 마커, 데이터 레이어 등 JS API의 모든 기능을 사용할 수 있습니다.
HTTP referrer로 웹 키를 제한하세요. iOS에서는 Capacitor가 앱을 capacitor://localhost 기본적으로 제공하며, Android에서는 https://localhost제공하므로, 해당 origin들을 키 제한에 추가하고 둘 다 테스트하세요.
옵션 4: 다른 SDK로 빌드된 네이티브 플러그인
커뮤니티에는 MapLibre Native 또는 Mapbox SDK용 네이티브 래퍼가 있습니다. 어떤 타일 소스에서도 네이티브 제스처와 성능을 제공합니다. 선택하기 전에 Capacitor 8 지원, 최근 릴리스 여부, iOS에서의 Swift Package Manager 지원(새 Capacitor 8 iOS 프로젝트의 기본), 필요한 오버레이 유형 지원을 확인하세요. 네이티브 지도 플러그인은 공식 플러그인과 같은 레이어링 트레이드오프를 가집니다. 지도가 네이티브 뷰이므로 HTML은 그 주변에 레이아웃해야 합니다.
@capacitor/google-maps를 유지해야 하는 경우
- Google의 기본 지도, Places 및 Street View 데이터가 필요합니다.
- 지도가 스크롤 콘텐츠 안의 작은 카드가 아니라 전체 화면 뷰입니다.
- 마커를 이동할 때 제거 후 추가하는 방식을 감수하거나, 위치를 거의 업데이트하지 않아도 됩니다.
그대로 유지한다면, 위의 투명도 CSS를 설정하고 <capacitor-google-map> 요소에 명시적 크기를 지정하고, 호출하세요. destroy() 페이지를 떠날 때 설정하세요. skipLibCheck: true 에서 tsconfig.json 플러그인 README에서 요구하는 대로.
어떤 지도와도 잘 어울리는 플러그인
지도를 무엇으로 렌더링하든, 이 Capgo 플러그인은 WebView 지도가 자체적으로 할 수 없는 네이티브 부분을 담당합니다.
턴바이턴 내비게이션 위임
내비게이션을 직접 구축하는 것은 그 자체로 하나의 프로젝트입니다. 대부분의 앱은 대신 사용자가 선호하는 내비게이션 앱을 엽니다. @capgo/capacitor-launch-navigator Apple Maps, Google Maps, Waze 등 다양한 서비스를 지원합니다:
import { LaunchNavigator, TransportMode } from '@capgo/capacitor-launch-navigator';
await LaunchNavigator.navigate({
destination: [48.8584, 2.2945], // [lat, lng]
options: { transportMode: TransportMode.DRIVING },
});
웹 서비스 없이 지오코딩하기
@capgo/capacitor-nativegeocoder iOS와 Android의 플랫폼 geocoder를 사용하므로 기기에서 Google 키가 필요 없습니다:
import { NativeGeocoder } from '@capgo/capacitor-nativegeocoder';
const { addresses } = await NativeGeocoder.reverseGeocode({
latitude: 48.8584,
longitude: 2.2945,
maxResults: 1,
});
console.log(addresses[0]?.thoroughfare, addresses[0]?.locality);
const result = await NativeGeocoder.forwardGeocode({
addressString: '5 Avenue Anatole France, Paris',
maxResults: 1,
});
console.log(result.addresses[0]?.latitude, result.addresses[0]?.longitude);
웹에서는 플러그인이 Google의 API를 사용하며, 다음이 필요합니다: apiKey 옵션을 설정하세요.
백그라운드에서도 사용자 위치 표시
포그라운드에서 '파란 점'을 @capacitor/geolocation 표시하는 정도라면 충분합니다. 앱이 백그라운드에 있을 때도 추적을 유지하거나, 사용자가 장소에 진입할 때 이벤트를 트리거하려면 @capgo/background-geolocation를 사용하고, 선택한 지도에 좌표를 전달하세요.
Capacitor에서 지도 문제 해결하기
공식 플러그인 사용 시 Android에서 지도가 빈 화면으로 나옴. 부모 요소에 투명도가 적용되지 않았습니다. Chrome DevTools로 검사하려면 chrome://inspect 을 사용해 다음 요소 사이에 배경색이 있는지 확인하세요: <html> 와 지도 요소
지도 요소의 높이가 0입니다. 지도 컨테이너에는 고유 크기가 없습니다. 높이를 명시적으로 지정하거나, 부모 높이를 고정한 flex 레이아웃을 사용하세요.
Android에서 WebGL 지도가 흐릿하거나 느립니다. 기기의 System WebView가 최신인지 확인하고, 레이어 수를 줄이며, 라우트 변경 시마다 지도를 다시 생성하지 않도록 하세요. 한 번만 생성해 재사용하세요.
릴리스 빌드에서 타일이 로드되지 않습니다. Content Security Policy와 네트워크 보안 설정을 확인하고, 타일 호스트가 HTTPS인지 확인하세요.
타일 스타일 URL을 변경한 후 지도가 깨집니다. 스타일과 타일 URL은 그냥 JavaScript 설정입니다. 기존 사용자는 제공업체를 전환할 수 있습니다. Capgo Live Update 사용하기앱 스토어 출시 없이, 네이티브 code 변경 사항이 없다면 가능합니다.
선택 기준
- 전체 화면 지도에서 Google 데이터와 네이티브 성능이 필요하다면: 유지
@capacitor/google-maps. - 커스텀 스타일링, Google 과금 없이, HTML처럼 동작하는 지도가 필요하다면: MapLibre GL JS.
- 마커 몇 개만 있는 간단한 지도가 필요하다면: Leaflet.
- 스크롤 레이아웃에서 Google 스타일이 필요하다면: WebView에서 Google Maps JS API.
무엇을 선택하든 저사양 Android 기기에서 미리 테스트하세요. 더 많은 네이티브 빌딩 블록은 다음을 둘러보세요: 그리고 Capgo 플러그인 디렉토리.