Xamarin.Forms Map Initialization and Configuration
The Map
control uses the native map control on each platform. This provides a fast, familiar maps experience for users, but means that some configuration steps are needed to adhere to each platforms API requirements.
Map initialization
The Map
control is provided by the Xamarin.Forms.Maps NuGet package, which should be added to every project in the solution.
After installing the Xamarin.Forms.Maps NuGet package, it must be initialized in each platform project.
On iOS, this should occur in AppDelegate.cs by invoking the Xamarin.FormsMaps.Init
method after the Xamarin.Forms.Forms.Init
method:
Xamarin.FormsMaps.Init();
On Android, this should occur in MainActivity.cs by invoking the Xamarin.FormsMaps.Init
method after the Xamarin.Forms.Forms.Init
method:
Xamarin.FormsMaps.Init(this, savedInstanceState);
On the Universal Windows Platform (UWP), this should occur in MainPage.xaml.cs by invoking the Xamarin.FormsMaps.Init
method from the MainPage
constructor:
Xamarin.FormsMaps.Init("INSERT_AUTHENTICATION_TOKEN_HERE");
For information about the authentication token required on UWP, see Universal Windows Platform.
Once the NuGet package has been added and the initialization method called inside each application, Xamarin.Forms.Maps
APIs can be used in the shared code project.
Platform configuration
Additional configuration is required on Android and the Universal Windows Platform (UWP) before the map will display. In addition, on iOS, Android, and UWP, accessing the user's location requires location permissions to have been granted to the application.
iOS
Displaying and interacting with a map on iOS doesn't require any additional configuration. However, to access location services, you must set the following keys in Info.plist:
- iOS 11 and later
NSLocationWhenInUseUsageDescription
– for using location services when the application is in useNSLocationAlwaysAndWhenInUseUsageDescription
– for using location services at all times
- iOS 10 and earlier
NSLocationWhenInUseUsageDescription
– for using location services when the application is in useNSLocationAlwaysUsageDescription
– for using location services at all times
To support iOS 11 and earlier, you can include all three keys: NSLocationWhenInUseUsageDescription
, NSLocationAlwaysAndWhenInUseUsageDescription
, and NSLocationAlwaysUsageDescription
.
The XML representation for these keys in Info.plist is shown below. You should update the string
values to reflect how your application is using the location information:
<key>NSLocationAlwaysUsageDescription</key>
<string>Can we use your location at all times?</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Can we use your location when your application is being used?</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Can we use your location at all times?</string>
The Info.plist entries can also be added in Source view while editing the Info.plist file:
A prompt is then displayed when the application attempts to access the user's location, requesting access:
Android
The configuration process for displaying and interacting with a map on Android is:
- Get a Google Maps API key and add it to the manifest.
- Specify the Google Play services version number in the manifest.
- Specify the requirement for Apache HTTP Legacy library in the manifest.
- [optional] Specify the WRITE_EXTERNAL_STORAGE permission in the manifest.
- [optional] Specify location permissions in the manifest.
- [optional] Request runtime location permissions in the
MainActivity
class.
For an example of a correctly configured manifest file, see AndroidManifest.xml from the sample application.
Get a Google Maps API key
To use the Google Maps API on Android you must generate an API key. To do this, follow the instructions in Obtaining a Google Maps API key.
Once you've obtained an API key it must be added within the <application>
element of the Properties/AndroidManifest.xml file:
<application ...>
<meta-data android:name="com.google.android.geo.API_KEY" android:value="PASTE-YOUR-API-KEY-HERE" />
</application>
This embeds the API key into the manifest. Without a valid API key the Map
control will display a blank grid.
Note
com.google.android.geo.API_KEY
is the recommended metadata name for the API key. For backwards compatibility, the com.google.android.maps.v2.API_KEY
metadata name can be used, but only allows authentication to the Android Maps API v2.
For your APK to access Google Maps, you must include SHA-1 fingerprints and package names for every keystore (debug and release) that you use to sign your APK. For example, if you use one computer for debug and another computer for generating the release APK, you should include the SHA-1 certificate fingerprint from the debug keystore of the first computer and the SHA-1 certificate fingerprint from the release keystore of the second computer. Also remember to edit the key credentials if the app's Package Name changes. See Obtaining a Google Maps API key.
Specify the Google Play services version number
Add the following declaration within the <application>
element of AndroidManifest.xml:
<meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" />
This embeds the version of Google Play services that the application was compiled with, into the manifest.
Specify the requirement for the Apache HTTP legacy library
If your Xamarin.Forms application targets API 28 or higher, you must add the following declaration within the <application>
element of AndroidManifest.xml:
<uses-library android:name="org.apache.http.legacy" android:required="false" />
This tells the application to use the Apache Http client library, which has been removed from the bootclasspath
in Android 9.
Specify the WRITE_EXTERNAL_STORAGE permission
If your application targets API 22 or lower, it may be necessary to add the WRITE_EXTERNAL_STORAGE
permission to the manifest, as a child of the <manifest>
element:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
This is not required if your application targets API 23 or greater.
Specify location permissions
If your application needs to access the user's location, you must request permission by adding the ACCESS_COARSE_LOCATION
or ACCESS_FINE_LOCATION
permissions to the manifest (or both), as a child of the <manifest>
element:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.companyname.myapp">
...
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
</manifest>
The ACCESS_COARSE_LOCATION
permission allows the API to use WiFi or mobile data, or both, to determine the device's location. The ACCESS_FINE_LOCATION
permissions allows the API to use the Global Positioning System (GPS), WiFi, or mobile data to determine a precise a location as possible.
Alternatively, these permissions can be enabled by using the manifest editor to add the following permissions:
AccessCoarseLocation
AccessFineLocation
These are shown in the screenshot below:
Request runtime location permissions
If your application targets API 23 or later and needs to access the user's location, it must check to see if it has the required permission at runtime, and request it if it does not have it. This can be accomplished as follows:
In the
MainActivity
class, add the following fields:const int RequestLocationId = 0; readonly string[] LocationPermissions = { Manifest.Permission.AccessCoarseLocation, Manifest.Permission.AccessFineLocation };
In the
MainActivity
class, add the followingOnStart
override:protected override void OnStart() { base.OnStart(); if ((int)Build.VERSION.SdkInt >= 23) { if (CheckSelfPermission(Manifest.Permission.AccessFineLocation) != Permission.Granted) { RequestPermissions(LocationPermissions, RequestLocationId); } else { // Permissions already granted - display a message. } } }
Provided that the application is targeting API 23 or greater, this code performs a runtime permission check for the
AccessFineLocation
permission. If permission has not been granted, a permission request is made by calling theRequestPermissions
method.In the
MainActivity
class, add the followingOnRequestPermissionsResult
override:public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Permission[] grantResults) { if (requestCode == RequestLocationId) { if ((grantResults.Length == 1) && (grantResults[0] == (int)Permission.Granted)) // Permissions granted - display a message. else // Permissions denied - display a message. } else { base.OnRequestPermissionsResult(requestCode, permissions, grantResults); } }
This override handles the result of the permission request.
The overall effect of this code is that when the application requests the user's location, the following dialog is displayed which requests permission:
Universal Windows Platform
On UWP, your application must be authenticated before it can display a map and consume map services. To authenticate your application, you must specify a maps authentication key. For more information, see Request a maps authentication key. The authentication token should then be specified in the FormsMaps.Init("AUTHORIZATION_TOKEN")
method call, to authenticate the application with Bing Maps.
Note
On UWP, to use map services such as geocoding you must also set the MapService.ServiceToken
property to the authentication key value. This can be accomplished with the following line of code: Windows.Services.Maps.MapService.ServiceToken = "INSERT_AUTH_TOKEN_HERE";
.
In addition, if your application needs to access the user's location, you must enable the location capability in the package manifest. This can be accomplished as follows:
In Solution Explorer, double-click package.appxmanifest and select the Capabilities tab.
In the Capabilities list, check the box for Location. This add the
location
device capability to the package manifest file.<Capabilities> <!-- DeviceCapability elements must follow Capability elements (if present) --> <DeviceCapability Name="location"/> </Capabilities>
Release builds
UWP release builds use .NET native compilation to compile the application directly to native code. However, a consequence of this is that the renderer for the Map
control on UWP may be linked out of the executable. This can be fixed by using a UWP-specific overload of the Forms.Init
method in App.xaml.cs:
var assembliesToInclude = new [] { typeof(Xamarin.Forms.Maps.UWP.MapRenderer).GetTypeInfo().Assembly };
Xamarin.Forms.Forms.Init(e, assembliesToInclude);
This code passes the assembly in which the Xamarin.Forms.Maps.UWP.MapRenderer
class resides, to the Forms.Init
method. This ensures that the assembly isn't linked out of the executable by the .NET native compilation process.
Important
Failure to do this will result in the Map
control not appearing when running a release build.