@capacitor/google-maps
Google maps on Capacitor
Install
npm install @capacitor/google-maps
npx cap sync
API Keys
To use the Google Maps SDK on any platform, API keys associated with an account with billing enabled are required. These can be obtained from the Google Cloud Console. This is required for all three platforms, Android, iOS, and Javascript. Additional information about obtaining these API keys can be found in the Google Maps documentation for each platform.
iOS
The Google Maps SDK supports the use of showing the users current location via enableCurrentLocation(bool)
. To use this, Apple requires privacy descriptions to be specified in Info.plist
:
NSLocationWhenInUseUsageDescription
(Privacy - Location When In Use Usage Description
)
Read about Configuring Info.plist
in the iOS Guide for more information on setting iOS permissions in Xcode.
The main Google Maps SDK now supports running on simulators on Apple Silicon Macs, but make sure you have the latest version of Google-Maps-iOS-Utils installed.
If you added the previous workaround for getting the unreleased version, you can delete it now by removing this line from ios/App/Podfile
:
pod 'Google-Maps-iOS-Utils', :git => 'https://github.com/googlemaps/google-maps-ios-utils.git', :commit => '637954e5bcb2a879c11a6f2cead153a6bad5339f'
Then run pod update Google-Maps-iOS-Utils
from the ios/App/
folder:
cd ios/App
pod update Google-Maps-iOS-Utils
Android
The Google Maps SDK for Android requires you to add your API key to the AndroidManifest.xml file in your project.
<meta-data android:name="com.google.android.geo.API_KEY" android:value="YOUR_API_KEY_HERE"/>
To use certain location features, the SDK requires the following permissions to also be added to your AndroidManifest.xml:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Variables
This plugin will use the following project variables (defined in your app's variables.gradle
file):
googleMapsPlayServicesVersion
: version ofcom.google.android.gms:play-services-maps
(default:18.2.0
)googleMapsUtilsVersion
: version ofcom.google.maps.android:android-maps-utils
(default:3.8.2
)googleMapsKtxVersion
: version ofcom.google.maps.android:maps-ktx
(default:5.0.0
)googleMapsUtilsKtxVersion
: version ofcom.google.maps.android:maps-utils-ktx
(default:5.0.0
)kotlinxCoroutinesVersion
: version oforg.jetbrains.kotlinx:kotlinx-coroutines-android
andorg.jetbrains.kotlinx:kotlinx-coroutines-core
(default:1.7.3
)androidxCoreKTXVersion
: version ofandroidx.core:core-ktx
(default:1.12.0
)kotlin_version
: version oforg.jetbrains.kotlin:kotlin-stdlib
(default:1.9.10
)
Usage
The Google Maps Capacitor plugin ships with a web component that must be used to render the map in your application as it enables us to embed the native view more effectively on iOS. The plugin will automatically register this web component for use in your application.
For Angular users, you will get an error warning that this web component is unknown to the Angular compiler. This is resolved by modifying the module that declares your component to allow for custom web components.
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
@NgModule({
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
Include this component in your HTML and assign it an ID so that you can easily query for that element reference later.
<capacitor-google-map id="map"></capacitor-google-map>
On Android, the map is rendered beneath the entire webview, and uses this component to manage its positioning during scrolling events. This means that as the developer, you must ensure that the webview is transparent all the way through the layers to the very bottom. In a typically Ionic application, that means setting transparency on elements such as IonContent and the root HTML tag to ensure that it can be seen. If you can't see your map on Android, this should be the first thing you check.
On iOS, we render the map directly into the webview and so the same transparency effects are not required. We are investigating alternate methods for Android still and hope to resolve this better in a future update.
The Google Map element itself comes unstyled, so you should style it to fit within the layout of your page structure. Because we're rendering a view into this slot, by itself the element has no width or height, so be sure to set those explicitly.
capacitor-google-map {
display: inline-block;
width: 275px;
height: 400px;
}
Next, we should create the map reference. This is done by importing the GoogleMap class from the Capacitor plugin and calling the create method, and passing in the required parameters.
import { GoogleMap } from '@capacitor/google-maps';
const apiKey = 'YOUR_API_KEY_HERE';
const mapRef = document.getElementById('map');
const newMap = await GoogleMap.create({
id: 'my-map', // Unique identifier for this map instance
element: mapRef, // reference to the capacitor-google-map element
apiKey: apiKey, // Your Google Maps API Key
config: {
center: {
// The initial position to be rendered by the map
lat: 33.6,
lng: -117.9,
},
zoom: 8, // The initial zoom level to be rendered by the map
},
});
At this point, your map should be created within your application. Using the returned reference to the map, you can easily interact with your map in a number of way, a few of which are shown here.
const newMap = await GoogleMap.create({...});
// Add a marker to the map
const markerId = await newMap.addMarker({
coordinate: {
lat: 33.6,
lng: -117.9
}
});
// Move the map programmatically
await newMap.setCamera({
coordinate: {
lat: 33.6,
lng: -117.9
}
});
// Enable marker clustering
await newMap.enableClustering();
// Handle marker click
await newMap.setOnMarkerClickListener((event) => {...});
// Clean up map reference
await newMap.destroy();
Full Examples
Angular
import { GoogleMap } from '@capacitor/google-maps';
@Component({
template: `
<capacitor-google-map #map></capacitor-google-map>
<button (click)="createMap()">Create Map</button>
`,
styles: [
`
capacitor-google-map {
display: inline-block;
width: 275px;
height: 400px;
}
`,
],
})
export class MyMap {
@ViewChild('map')
mapRef: ElementRef<HTMLElement>;
newMap: GoogleMap;
async createMap() {
this.newMap = await GoogleMap.create({
id: 'my-cool-map',
element: this.mapRef.nativeElement,
apiKey: environment.apiKey,
config: {
center: {
lat: 33.6,
lng: -117.9,
},
zoom: 8,
},
});
}
}
React
import { GoogleMap } from '@capacitor/google-maps';
import { useRef } from 'react';
const MyMap: React.FC = () => {
const mapRef = useRef<HTMLElement>();
let newMap: GoogleMap;
async function createMap() {
if (!mapRef.current) return;
newMap = await GoogleMap.create({
id: 'my-cool-map',
element: mapRef.current,
apiKey: process.env.REACT_APP_YOUR_API_KEY_HERE,
config: {
center: {
lat: 33.6,
lng: -117.9
},
zoom: 8
}
})
}
return (
<div className="component-wrapper">
<capacitor-google-map ref={mapRef} style={{
display: 'inline-block',
width: 275,
height: 400
}}></capacitor-google-map>
<button onClick={createMap}>Create Map</button>
</div>
)
}
export default MyMap;
Javascript
<capacitor-google-map id="map"></capacitor-google-map>
<button onclick="createMap()">Create Map</button>
<style>
capacitor-google-map {
display: inline-block;
width: 275px;
height: 400px;
}
</style>
<script>
import { GoogleMap } from '@capacitor/google-maps';
const createMap = async () => {
const mapRef = document.getElementById('map');
const newMap = await GoogleMap.create({
id: 'my-map', // Unique identifier for this map instance
element: mapRef, // reference to the capacitor-google-map element
apiKey: 'YOUR_API_KEY_HERE', // Your Google Maps API Key
config: {
center: {
// The initial position to be rendered by the map
lat: 33.6,
lng: -117.9,
},
zoom: 8, // The initial zoom level to be rendered by the map
},
});
};
</script>
API
create(...)
enableTouch()
disableTouch()
enableClustering(...)
disableClustering()
addMarker(...)
addMarkers(...)
removeMarker(...)
removeMarkers(...)
addPolygons(...)
removePolygons(...)
addCircles(...)
removeCircles(...)
addPolylines(...)
removePolylines(...)
destroy()
setCamera(...)
getMapType()
setMapType(...)
enableIndoorMaps(...)
enableTrafficLayer(...)
enableAccessibilityElements(...)
enableCurrentLocation(...)
setPadding(...)
getMapBounds()
fitBounds(...)
setOnBoundsChangedListener(...)
setOnCameraIdleListener(...)
setOnCameraMoveStartedListener(...)
setOnClusterClickListener(...)
setOnClusterInfoWindowClickListener(...)
setOnInfoWindowClickListener(...)
setOnMapClickListener(...)
setOnMarkerClickListener(...)
setOnPolygonClickListener(...)
setOnCircleClickListener(...)
setOnPolylineClickListener(...)
setOnMarkerDragStartListener(...)
setOnMarkerDragListener(...)
setOnMarkerDragEndListener(...)
setOnMyLocationButtonClickListener(...)
setOnMyLocationClickListener(...)
- Interfaces
- Type Aliases
- Enums
create(...)
create(options: CreateMapArgs, callback?: MapListenerCallback<MapReadyCallbackData> | undefined) => Promise<GoogleMap>
Param | Type |
---|---|
options | CreateMapArgs |
callback | MapListenerCallback<MapReadyCallbackData> |
Returns: Promise<GoogleMap>
enableTouch()
enableTouch() => Promise<void>
disableTouch()
disableTouch() => Promise<void>
enableClustering(...)
enableClustering(minClusterSize?: number | undefined) => Promise<void>
Param | Type | Description |
---|---|---|
minClusterSize | number | The minimum number of markers that can be clustered together. The default is 4 markers. |
disableClustering()
disableClustering() => Promise<void>
addMarker(...)
addMarker(marker: Marker) => Promise<string>
Param | Type |
---|---|
marker | Marker |
Returns: Promise<string>
addMarkers(...)
addMarkers(markers: Marker[]) => Promise<string[]>
Param | Type |
---|---|
markers | Marker[] |
Returns: Promise<string[]>
removeMarker(...)
removeMarker(id: string) => Promise<void>
Param | Type |
---|---|
id | string |
removeMarkers(...)
removeMarkers(ids: string[]) => Promise<void>
Param | Type |
---|---|
ids | string[] |
addPolygons(...)
addPolygons(polygons: Polygon[]) => Promise<string[]>
Param | Type |
---|---|
polygons | Polygon[] |
Returns: Promise<string[]>
removePolygons(...)
removePolygons(ids: string[]) => Promise<void>
Param | Type |
---|---|
ids | string[] |
addCircles(...)
addCircles(circles: Circle[]) => Promise<string[]>
Param | Type |
---|---|
circles | Circle[] |
Returns: Promise<string[]>
removeCircles(...)
removeCircles(ids: string[]) => Promise<void>
Param | Type |
---|---|
ids | string[] |
addPolylines(...)
addPolylines(polylines: Polyline[]) => Promise<string[]>
Param | Type |
---|---|
polylines | Polyline[] |
Returns: Promise<string[]>
removePolylines(...)
removePolylines(ids: string[]) => Promise<void>
Param | Type |
---|---|
ids | string[] |
destroy()
destroy() => Promise<void>
setCamera(...)
setCamera(config: CameraConfig) => Promise<void>
Param | Type |
---|---|
config | CameraConfig |
getMapType()
getMapType() => Promise<MapType>
Get current map type
Returns: Promise<MapType>
setMapType(...)
setMapType(mapType: MapType) => Promise<void>
Param | Type |
---|---|
mapType | MapType |
enableIndoorMaps(...)
enableIndoorMaps(enabled: boolean) => Promise<void>