Capacitor Google Maps Plugin

repository·main·Indexed 41 days ago

https://github.com/capacitor-community/google-maps

A Capacitor plugin providing native Google Maps SDK integration for Android and iOS (version 2.0.0-beta.18). It renders native maps behind a transparent WebView for better performance and offline support compared to the JavaScript SDK. Features include map lifecycle management (createMap, updateMap, removeMap), marker manipulation, camera control, and a comprehensive set of interaction events for markers, POIs, and camera movement.

Tokens
17.1K
Snippets
62
Records
85
Agent score
50%

What's inside Capacitor Google Maps

  1. Overview of @capacitor-community/google-maps

    main

    The @capacitor-community/google-maps plugin provides Capacitor developers with access to the native Google Maps SDK for Android and iOS.

    Key Benefits

    • Performance: Uses native SDKs which offer significantly better performance than the JavaScript-based equivalent.
    • Offline Support: Enables support for offline caching via the native SDKs.
    • Cost Efficiency: Uses 'Dynamic Maps' via the native SDK, which is free to use (as of February 2022), unlike the Google Maps JavaScript SDK which follows a different pricing model.

    Important Limitations

    • Fixed Positioning: The rendered Map view cannot currently scroll along with the page; it remains at a fixed position.
    • Platform Support: This plugin only supports native iOS and Android SDKs. It does not include a web implementation (JavaScript SDK). If you require web support, you must implement the JavaScript SDK separately.
  2. Configure MapAppearance

    main

    The MapAppearance object aggregates parameters related to the visual state of the map. This includes:

    • Showing 3D buildings
    • Showing indoor maps
    • Showing the my-location (blue) dot
    • Showing traffic layers
    • Setting the type of map tiles
    • Setting the overall styling of the base map
  3. How the Transparent WebView works

    main

    The Google Maps plugin works by rendering a native Google Maps instance (Android, iOS) behind the Capacitor WebView. Because the native map is not an HTML element, the plugin makes the WebView transparent so that the native map is visible through it.

    This architecture allows you to render any kind of HTMLElement (like <div>, <span>, or custom components) on top of the native Map.

    Note: To ensure touch events work correctly between the HTML layer and the native map layer, refer to the Touch Delegation guide.

  4. Configure CameraPosition

    main

    The map view is controlled by a camera. You can specify the CameraPosition to change what the user sees. Properties include:

    • target (LatLng): The latitude/longitude coordinates that will be at the center of the map.
    • bearing (number): The direction the map points, in degrees clockwise from north (e.g., 90 is East).
    • tilt (number): The viewing angle in degrees from the nadir (directly below the camera).
    • zoom (number): The scale of the map.
    const position: CameraPosition = {
      target: { latitude: 37.7749, longitude: -122.4194 },
      bearing: 0,
      tilt: 0,
      zoom: 12
    };
  5. How the Map rendering works

    main

    The Maps SDK does not render inside the webview as a standard HTMLElement. Instead, it renders a native element (MapView) behind your webapp (WebView).

    Key implications:

    • The map cannot be styled, mutated, or listened to using standard DOM methods like you would with a normal HTMLElement.
    • The map instance does not automatically resize or move with the div it is attached to.
    • To ensure the map is visible and correctly positioned, the 'foster element' (the HTML element you attach the map to) should remain at a fixed position. It is recommended to prevent scrolling and use a fixed orientation (portrait or landscape) for the foster element.
  6. Ensure Map visibility by managing CSS transparency

    main

    While the plugin automatically attempts to make the WebView and the <html> element transparent, your own application's CSS might overwrite these settings and hide the map.

    To ensure the map is viewable, you must ensure that your web application's background elements (especially the <html> and <body> tags) do not have a solid background color that covers the map. If the map is not appearing, consult the Setup WebView guide to verify your CSS transparency settings.

  7. Add API keys to your Android app

    main

    To add your Android API key, follow the official Google guide (specifically "Step 2: Add your API key to the project").

    Warning: You can manually add the key to AndroidManifest.xml for testing, but this is not recommended for production as it can lead to API key leakage.

    Testing only method: In your AndroidManifest.xml, add the following inside the <application> tag:

    <application>
      ...
      <meta-data
        android:name="com.google.android.geo.API_KEY"
        android:value="YOUR_ANDROID_MAPS_API_KEY"/>
      ...
    </application>
    <application>
    ...
    +  <meta-data
    +    android:name="com.google.android.geo.API_KEY"
    +    android:value="YOUR_ANDROID_MAPS_API_KEY"/>
    ...
    </application>
  8. Initialize and create a Map instance

    main

    To display a map, you must first initialize the SDK with your API key and then create a map instance by providing the bounding rectangle of a 'foster element' in your HTML.

    Steps:

    1. Initialize the SDK: Call CapacitorGoogleMaps.initialize() with your API key and the current window.devicePixelRatio.
    2. Identify the Foster Element: Select the HTML element where the map should appear.
    3. Calculate Boundaries: Use getBoundingClientRect() to get the element's position and size.
    4. Create the Map: Call CapacitorGoogleMaps.createMap() using the calculated boundaries.
    5. Prepare the UI:
      • Remove the background color of the foster element so the native map is visible through the WebView.
      • Set the data-maps-id attribute on the foster element using the mapId from the result to allow the plugin to delegate touch events correctly.
    import { CapacitorGoogleMaps } from "@capacitor-community/google-maps";
    
    const initializeMap = async () => {
      // 1. Initialize the Maps SDK
      await CapacitorGoogleMaps.initialize({
        key: "YOUR_IOS_MAPS_API_KEY",
        devicePixelRatio: window.devicePixelRatio, // This line is critical
      });
    
      // 2. Get the foster element
      const element = document.getElementById("container");
    
      // 3. Get boundaries
      const boundingRect = element.getBoundingClientRect();
    
      try {
        // 4. Create the map
        const result = await CapacitorGoogleMaps.createMap({
          boundingRect: {
            width: Math.round(boundingRect.width),
            height: Math.round(boundingRect.height),
            x: Math.round(boundingRect.x),
            y: Math.round(boundingRect.y),
          },
        });
    
        // 5. Prepare the UI
        // Remove background so map can be seen
        element.style.background = "";
    
        // Set data-maps-id for touch event delegation
        element.setAttribute("data-maps-id", result.googleMap.mapId);
    
        alert("Map loaded successfully");
      } catch (e) {
        alert("Map failed to load");
      }
    };
    
    initializeMap();
  9. Determine if the Google Maps plugin is right for your project

    main

    Deciding whether to use the @capacitor-community/google-maps plugin depends on your app's core functionality, performance requirements, and budget. This plugin uses the native Maps SDK for Android and iOS, which offers better performance and offline caching support compared to the JavaScript SDK.

    Use this plugin if:

    • Map-centric apps: Your app's primary purpose revolves around maps (e.g., ride-sharing or scooter-sharing apps).
    • Performance needs: You need to render many markers or require high-performance map interactions.
    • Cost optimization: You want to leverage the native 'Dynamic Maps' pricing, which may be more cost-effective than the JavaScript SDK depending on your usage.

    Avoid this plugin if:

    • Static displays: You only need to show a single location (e.g., a restaurant address). In this case, using a free Google Maps iframe embed is simpler and more cost-effective.
    • Existing JS SDK success: You are already using the Google Maps JavaScript SDK and are not experiencing performance issues or exceeding free tier limits. The overhead of implementing the native plugin may not be justified.
  10. Implement Geocoding and Reverse Geocoding

    main

    Geocoding (converting addresses to coordinates) and Reverse Geocoding (converting coordinates to addresses) are not implemented in this plugin. You can implement these features using the official Google Maps Geocoding API via direct HTTP requests or the official JavaScript SDK.

    Geocoding (Address to Coordinates)

    Direct API URL: https://maps.googleapis.com/maps/api/geocode/json?address=ADDRESS&key=YOUR_API_KEY

    Using JavaScript SDK:

    geocoder
      .geocode({ address: "Some address" })
      .then((response) => {
        if (response.results[0]) {
          console.log(response.results);
        } else {
          console.log("No results found");
        }
      })
      .catch((e) => console.error(e));

    Reverse Geocoding (Coordinates to Address)

    Direct API URL: https://maps.googleapis.com/maps/api/geocode/json?latlng=LAT,LNG&key=YOUR_API_KEY

    Using JavaScript SDK:

    geocoder
      .geocode({ location: { lat: 40.731, lng: -73.997 } })
      .then((response) => {
        if (response.results[0]) {
          console.log(response.results);
        } else {
          console.log("No results found");
        }
      })
      .catch((e) => console.error(e));
    geocoder
      .geocode({ address: "Some address" })
      .then((response) => {
        if (response.results[0]) {
          console.log(response.results);
        } else {
          console.log("No results found");
        }
      })
      .catch((e) => console.error(e));