
Maui Maps
- 30 installs
- 163 repo stars
- Updated July 6, 2026
- davidortinau/maui-skills
Adds map controls, pins, polygons, polylines, and geocoding to .NET MAUI apps using Microsoft.Maui.Controls.Maps.
About
Guides adding map controls, pins, polygons, polylines and geocoding to .NET MAUI apps, including Google Maps API key configuration and platform setup. A developer uses it when embedding interactive maps in a MAUI app.
- Map controls with pins, polygons, and polylines
- Geocoding and Google Maps API key configuration
Maui Maps by the numbers
- 30 all-time installs (skills.sh)
- Ranked #665 of 1,039 Mobile Development skills by installs in the Skillselion catalog
- Data as of Aug 3, 2026 (Skillselion catalog sync)
npx skills add https://github.com/davidortinau/maui-skills --skill maui-mapsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 30 |
|---|---|
| repo stars | ★ 163 |
| Last updated | July 6, 2026 |
| Repository | davidortinau/maui-skills ↗ |
What it does
Adds map controls, pins, polygons, polylines, and geocoding to .NET MAUI apps using Microsoft.Maui.Controls.Maps.
Files
.NET MAUI Maps
Common gotchas
| Issue | Fix |
|---|---|
| Map is blank on Android | Google Maps API key missing or wrong in AndroidManifest.xml |
| Map crashes on startup | .UseMauiMaps() not called in MauiProgram.cs |
Map type ambiguous | Conflicts with Microsoft.Maui.ApplicationModel.Map — add namespace alias |
| Map doesn't show on Windows | Windows has no native support — must use CommunityToolkit.Maui.Maps |
| User location dot missing | IsShowingUser="True" set but location permission not granted |
| Android 11+ can't launch external map app | Missing <queries> for geo scheme in manifest |
⚠️ Name conflict — always alias
Microsoft.Maui.Controls.Maps.Map conflicts with Microsoft.Maui.ApplicationModel.Map. This causes confusing compile errors.
// ✅ Correct — explicit alias
using Map = Microsoft.Maui.Controls.Maps.Map;<!-- ✅ Correct — namespace prefix in XAML -->
xmlns:maps="clr-namespace:Microsoft.Maui.Controls.Maps;assembly=Microsoft.Maui.Controls.Maps"
<maps:Map ... />
<!-- ❌ Wrong — bare <Map> is ambiguous -->
<Map ... />Platform setup pitfalls
Android — API key must be inside <application>
<!-- ✅ Correct -->
<application ...>
<meta-data android:name="com.google.android.geo.API_KEY"
android:value="YOUR_GOOGLE_MAPS_KEY" />
</application>
<!-- ❌ Outside <application> — key is silently ignored -->⚠️ Also required: Google Play Services version meta-data and <queries> for geo scheme on API 30+ (see references/maps-api.md).
iOS / Mac Catalyst
⚠️ Without NSLocationWhenInUseUsageDescription in Info.plist, location permission is denied without prompt.
Windows — no native support
Must add CommunityToolkit.Maui.Maps + Bing key. Use conditional package reference and #if WINDOWS for setup.
MauiProgram.cs — don't forget UseMauiMaps
// ✅ Required — without this, Map control throws at runtime
builder.UseMauiMaps();
// ❌ Forgetting this causes "No registered handler for Map" crashPerformance tips
- ⚠️ Don't add hundreds of pins directly — use
ItemsSourcewith data binding for large pin sets. - Set initial region with
MoveToRegion()to avoid the default world view zoom animation. - Avoid frequent `MoveToRegion()` calls — each triggers a map animation; debounce if driven by data changes.
Data-bound pins — do this for dynamic data
<!-- ✅ Correct — data-bound pins for dynamic collections -->
<maps:Map ItemsSource="{Binding Locations}">
<maps:Map.ItemTemplate>
<DataTemplate>
<maps:Pin Label="{Binding Name}"
Address="{Binding Description}"
Location="{Binding Position}" />
</DataTemplate>
</maps:Map.ItemTemplate>
</maps:Map>
<!-- ❌ Wrong — manually adding pins in code-behind for data-driven scenarios -->Decision framework
| Need | Approach |
|---|---|
| Basic map with pins | Map control + Pins.Add() or ItemsSource binding |
| Map with shapes | MapElements — Polygon, Polyline, Circle |
| Address → coordinates | Geocoding.Default.GetLocationsAsync(address) |
| Coordinates → address | Geocoding.Default.GetPlacemarksAsync(lat, lon) |
| Custom map overlays | Use handlers to access native map APIs |
| Windows support | Must add CommunityToolkit.Maui.Maps + Bing key |
Quick checklist
- [ ] NuGet:
Microsoft.Maui.Controls.Mapsadded - [ ]
.UseMauiMaps()called inMauiProgram.cs - [ ] Android: Google Maps API key inside
<application>inAndroidManifest.xml - [ ] Android: Google Play Services version meta-data present
- [ ] Android 11+:
<queries>for geo scheme added - [ ] iOS/Mac:
NSLocationWhenInUseUsageDescriptioninInfo.plist - [ ] Windows:
CommunityToolkit.Maui.Maps+ Bing Maps key (conditional) - [ ] Namespace alias added to avoid
Maptype conflict
Maps API Reference
NuGet Package
Install Microsoft.Maui.Controls.Maps (and on Windows, CommunityToolkit.Maui.Maps):
<ItemGroup>
<PackageReference Include="Microsoft.Maui.Controls.Maps" Version="$(MauiVersion)" />
<!-- Windows only – Bing Maps via Community Toolkit -->
<PackageReference Include="CommunityToolkit.Maui.Maps"
Version="*"
Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'" />
</ItemGroup>MauiProgram.cs Setup
using Microsoft.Maui.Controls.Hosting;
using Microsoft.Maui.Hosting;
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.UseMauiMaps(); // <-- required
#if WINDOWS
.UseMauiCommunityToolkitMaps("YOUR_BING_MAPS_KEY");
#endif
return builder.Build();
}Platform Setup
Android – Google Maps API Key
1. Obtain a key from the Google Cloud Console with the Maps SDK for Android API enabled. 2. Add the key to Platforms/Android/AndroidManifest.xml:
<application ...>
<meta-data android:name="com.google.android.geo.API_KEY"
android:value="YOUR_GOOGLE_MAPS_KEY" />
</application>3. Ensure Google Play Services version meta-data is present:
<meta-data android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />4. For Android 11+ (API 30), add package visibility queries so the app can launch external map intents:
<queries>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="geo" />
</intent>
</queries>5. Required permissions (usually auto-merged): ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION, INTERNET.
iOS / Mac Catalyst
Add to Platforms/iOS/Info.plist (and Platforms/MacCatalyst/Info.plist):
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs your location to show it on the map.</string>Windows
Maps are not natively supported by Microsoft.Maui.Controls.Maps on Windows. Use CommunityToolkit.Maui.Maps which renders Bing Maps in a WebView2 control.
Core Map Properties
| Property | Type | Description |
|---|---|---|
MapType | MapType | Street, Satellite, or Hybrid |
IsShowingUser | bool | Show the user's current location |
IsScrollEnabled | bool | Allow panning |
IsZoomEnabled | bool | Allow zoom gestures |
IsTrafficEnabled | bool | Show traffic overlay |
<maps:Map MapType="Hybrid"
IsShowingUser="True"
IsScrollEnabled="True"
IsZoomEnabled="True"
IsTrafficEnabled="False" />Pins
var pin = new Pin
{
Label = "Microsoft HQ",
Address = "One Microsoft Way, Redmond, WA",
Location = new Location(47.6423, -122.1391),
Type = PinType.Place // Place | Generic | SearchResult | SavedPin
};
pin.MarkerClicked += (s, e) => { e.HideInfoWindow = true; };
pin.InfoWindowClicked += (s, e) => { /* navigate or show details */ };
map.Pins.Add(pin);Map Elements – Polygon, Polyline, Circle
// Polygon
var polygon = new Polygon
{
StrokeColor = Colors.Blue,
StrokeWidth = 2,
FillColor = Color.FromRgba(0, 0, 255, 64)
};
polygon.Geopath.Add(new Location(47.64, -122.13));
polygon.Geopath.Add(new Location(47.65, -122.13));
polygon.Geopath.Add(new Location(47.65, -122.14));
map.MapElements.Add(polygon);
// Polyline
var polyline = new Polyline
{
StrokeColor = Colors.Red,
StrokeWidth = 5
};
polyline.Geopath.Add(new Location(47.64, -122.13));
polyline.Geopath.Add(new Location(47.65, -122.14));
map.MapElements.Add(polyline);
// Circle
var circle = new Circle
{
Center = new Location(47.64, -122.13),
Radius = new Distance(500),
StrokeColor = Colors.Green,
FillColor = Color.FromRgba(0, 128, 0, 64)
};
map.MapElements.Add(circle);Moving the Map Viewport
var center = new Location(47.6423, -122.1391);
var span = MapSpan.FromCenterAndRadius(center, Distance.FromKilometers(2));
map.MoveToRegion(span);MapClicked Event
map.MapClicked += (s, e) =>
{
var location = e.Location; // Location (lat/lon)
System.Diagnostics.Debug.WriteLine(
$"Map clicked at {location.Latitude}, {location.Longitude}");
};Data-Bound Pins (ItemsSource / ItemTemplate)
<maps:Map ItemsSource="{Binding Locations}">
<maps:Map.ItemTemplate>
<DataTemplate>
<maps:Pin Label="{Binding Name}"
Address="{Binding Description}"
Location="{Binding Position}" />
</DataTemplate>
</maps:Map.ItemTemplate>
</maps:Map>public class LocationViewModel
{
public string Name { get; set; }
public string Description { get; set; }
public Location Position { get; set; }
}Geocoding Integration
Use Microsoft.Maui.Devices.Sensors.Geocoding to convert addresses ↔ coordinates:
var locations = await Geocoding.Default.GetLocationsAsync("Redmond, WA");
var location = locations?.FirstOrDefault();
if (location is not null)
{
map.MoveToRegion(MapSpan.FromCenterAndRadius(
new Location(location.Latitude, location.Longitude),
Distance.FromKilometers(5)));
}Reverse geocoding:
var placemarks = await Geocoding.Default.GetPlacemarksAsync(47.64, -122.13);
var placemark = placemarks?.FirstOrDefault();
// placemark.Locality, placemark.AdminArea, placemark.CountryName, etc.