De inhoud van deze handleiding is echter grotendeels vervangen door Xamarin.Essentials.
Inhoud
- Wat vooraf ging
- Inleiding
- Mappen – integreren
- Mappen – gebruiken
- Mappen – Praktisch voorbeeld
- GPS lokalisatie – integreren
- GPS lokalisatie – gebruiken
- GPS lokalisatie + mappen – videovoorbeeld
Wat vooraf ging
- U hebt weet hoe een Xamarin-project opgebouwd is.
- U kunt een pagina dynamisch opbouwen via programmeercode.
Ik herneem hier even een vorige post over het installeren van NuGet Packages (plug-ins).
NuGet is een package manager voor Microsoft development platforms zoals .NET. U kunt deze pakketten installeren om zo de mogelijkheden van uw project uit te breiden.
- Om een NuGet package te installeren klikt u rechts op het project waar u het NuGet package wilt voor installeren of u klikt rechts op de Solution om het NuGet package meteen te installeren voor alle projecten.
- Vervolgens klikt u op Manage NuGet packages for Solution….
- Selecteer het NuGet package dat u wil installeren.
- Vink alle projecten aan waarvoor u het wilt installeren.
- Klik op Install.
Onderstaande video toont een volledige installatie (zij het in Visual Studio 2015 en voor een ASP.NET project maar in weze verschilt dit niet).
Inleiding
Er komen twee topics aan bod die allen te maken hebben met lokalisatie.
- Mappen integreren
- Geolokalisatie opvragen
Mappen – integreren
Xamarin.Forms.Maps maakt gebruik van de native map-API’s op elk platform. Dit biedt een snelle, vertrouwde kaartenervaring voor gebruikers, maar betekent dat er enkele configuratiestappen nodig zijn om te voldoen aan elke platformspecifieke API-vereisten.
Plug-in installeren
- Klik rechts op de Solution om het NuGet package meteen te installeren voor alle projecten.
- Vervolgens klikt u op Manage NuGet packages for Solution….
- Klik op Browse.
- Zoek naar Xamarin.Forms.Maps, selecteer alle projecten en de laatste stabiele versie en klik op Install.
Sleutels aanvragen
Om optimaal gebruik te kunnen maken van de mappen op Android en UWP (niet op iOS) moet een sleutel opgevraagd worden.
- Android – hier kunt u de sleutel opvragen en hier vindt u de nodige stappen.
- UWP – hier kunt u de sleutel opvragen en hier vindt u de nodige stappen.
Remember to generate another key using the keystore file that is used to sign the Release version of any application that is uploaded to the Google Play store. The key you generate for development and debugging will not work and the app downloaded from Google Play will have broken map display. Also remember to regenerate the key if the app’s Package Name changes.
Permissies instellen
Uw app moet toegang krijgen/vragen tot de lokalisatie van het toestel.
UWP
In UWP is dit vrij eenvoudig, u moet de applicatie enkel toegang geven tot de Location.
- Open Properties onder het UWP-project.
- Ga naar Application en klik op Package Manifest….
- Selecteer het tabblad Capabilities en vink Location aan.
Android
Voor Android moeten onderstaande permissies ingesteld worden:
- AccessCoarseLocation
- AccessFineLocation
- AccessLocationExtraCommands
- AccessMockLocation
- AccessNetworkState
- AccessWifiState
- Internet
U stelt deze in via:
- Open Properties onder het Android-project.
- Ga naar Android Manifest.
- Vink bovenstaande permissies aan.
U dient ook nog de opgevraagde sleutel toe te voegen.
- Voeg onderstaande code toe aan AndroidManifest.xml, binnen de Application-tag dat u vindt onder het Android-project.
<meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="AbCdEfGhIjKlMnOpQrStUvWValueGoesHere" />
De volledige code voor AndroidManifest.xml is:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.xamarin.mobilecrm"> <uses-sdk android:minSdkVersion="15" /> <application android:label="WorkingWithMaps.Android"> <meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="AbCdEfGhIjKlMnOpQrStUvWValueGoesHere" /> <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" /> </application> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" /> <uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> </manifest>
Merk op dat u hier de permissies terugvindt die u via Properties – Android Manifest hebt ingesteld. U had ze ook hier kunnen toevoegen.
iOS
Voor iOS dient u een aantal keys, en bijhorende meldingen die verschijnen wanneer u er gebruik van wilt maken, toevoegen aan het bestandje Info.plist.
- Klik rechts Info.plist dat u vindt onder het iOS-project en kies voor Open with… en selecteer XML (Text) Editor.
- Voeg onderstaande code toe.
<key>NSLocationWhenInUseUsageDescription</key> <string>We are using your location</string> <key>NSLocationAlwaysUsageDescription</key> <string>Can we use your location</string> <key>NSLocationAlwaysAndWhenInUseUsageDescription</key> <string>This app needs access location when open and in the background.</string>
De volledige code, van de voorbeeldapplicatie die we hieronder gaan gebruiken, is:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>CFBundleIdentifier</key> <string>com.xamarin.WorkingWithMaps.iOS</string> <key>CFBundleShortVersionString</key> <string>1.0</string> <key>CFBundleVersion</key> <string>1.0</string> <key>LSRequiresIPhoneOS</key> <true/> <key>MinimumOSVersion</key> <string>9.0</string> <key>UIDeviceFamily</key> <array> <integer>1</integer> <integer>2</integer> </array> <key>UIRequiredDeviceCapabilities</key> <array> <string>armv7</string> </array> <key>UISupportedInterfaceOrientations</key> <array> <string>UIInterfaceOrientationPortrait</string> <string>UIInterfaceOrientationLandscapeLeft</string> <string>UIInterfaceOrientationLandscapeRight</string> </array> <key>UISupportedInterfaceOrientations~ipad</key> <array> <string>UIInterfaceOrientationPortrait</string> <string>UIInterfaceOrientationPortraitUpsideDown</string> <string>UIInterfaceOrientationLandscapeLeft</string> <string>UIInterfaceOrientationLandscapeRight</string> </array> <key>CFBundleDisplayName</key> <string>Maps</string> <key>NSLocationWhenInUseUsageDescription</key> <string>We are using your location</string> <key>NSLocationAlwaysUsageDescription</key> <string>Can we use your location</string> <key>NSLocationAlwaysAndWhenInUseUsageDescription</key> <string>This app needs access location when open and in the background.</string> <key>CFBundleName</key> <string>Maps</string> </dict> </plist>
Initialisatie
U moet het gebruik van mappen ook nog initialiseren.
UWP
- Voeg onderstaande code toe aan MainPage.xaml.cs, binnen de constructor, dat u vindt onder het UWP-project.
Xamarin.FormsMaps.Init("INSERT_AUTHENTICATION_TOKEN_HERE");
De volledige code:
namespace WorkingWithMaps.UWP { public sealed partial class MainPage { public MainPage() { this.InitializeComponent(); Xamarin.FormsMaps.Init("INSERT_AUTHENTICATION_TOKEN_HERE"); this.LoadApplication(new WorkingWithMaps.App()); } } }
Android
- Voeg onderstaande code toe aan MainActivity.cs, binnen de OnCreate-methode dat u vindt onder het Android-project.
Xamarin.FormsMaps.Init(this, bundle);
De volledige code:
using Android.App; using Android.OS; using Android.Content.PM; namespace WorkingWithMaps.Android { [Activity (Label = "WorkingWithMaps.Android.Android", Icon = "@drawable/icon", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)] public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsApplicationActivity // superclass new in 1.3 { protected override void OnCreate (Bundle bundle) { base.OnCreate (bundle); global::Xamarin.Forms.Forms.Init (this, bundle); global::Xamarin.FormsMaps.Init (this, bundle); LoadApplication (new App ()); // method is new in 1.3 } } }
iOS
- Voeg onderstaande code toe aan AppDelegate.cs, binnen de FinishedLaunching-methodedat u vindt onder het iOS-project.
Xamarin.FormsMaps.Init();
De volledige code:
using Foundation; using UIKit; namespace WorkingWithMaps.iOS { [Register ("AppDelegate")] public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate // superclass new in 1.3 { public override bool FinishedLaunching (UIApplication app, NSDictionary options) { global::Xamarin.Forms.Forms.Init (); global::Xamarin.FormsMaps.Init (); LoadApplication (new App ()); // method is new in 1.3 return base.FinishedLaunching (app, options); } } }
Mappen – gebruiken
Onderstaande code-snippets tonen hoe u mappen kan gebruiken. Er zal hoofdzakelijk C# worden gebruikt. Enkel de map plaatsen kan eventueel in XAML.
Begin met de gewenste namespace toe te voegen.
using Xamarin.Forms.Maps;
Map aanmaken
C#
public class MapPage : ContentPage { public MapPage() { var map = new Map( MapSpan.FromCenterAndRadius( new Position(37,-122), Distance.FromMiles(0.3))) { IsShowingUser = true, HeightRequest = 100, WidthRequest = 960, VerticalOptions = LayoutOptions.FillAndExpand }; var stack = new StackLayout { Spacing = 0 }; stack.Children.Add(map); Content = stack; } }
Merk op dat IsShowingUser = true,
die de plaats van de gebruiker weergeeft, op het ogenblik van dit schrijven een fout veroorzaakt en misschien zal moeten weggelaten worden (of in commentaar plaatsen).
De MapSpan.FromCenterAndRadius(new Position(37,-122), Distance.FromMiles(0.3)))
bepaalt de weergegeven positie.
U zou ook naar een bepaalde regio kunnen gaan via map.MoveToRegion (new MapSpan (new Position (0,0), 360, 360) );
XAML
<?xml version="1.0" encoding="UTF-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:maps="clr-namespace:Xamarin.Forms.Maps;assembly=Xamarin.Forms.Maps" x:Class="MapDemo.MapPage"> <StackLayout VerticalOptions="StartAndExpand" Padding="30"> <maps:Map WidthRequest="320" HeightRequest="200" x:Name="MyMap" IsShowingUser="true" MapType="Hybrid" /> </StackLayout> </ContentPage>
Merk het toevoegen van de namespace op xmlns:maps="clr-namespace:Xamarin.Forms.Maps;assembly=Xamarin.Forms.Maps"
.
Het verplaatsen naar een specifiek punt op de map dient dan weer in C# te gebeuren.
MyMap.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(37,-122), Distance.FromMiles(1)));
In- en uitzoomen
Gebruik een Slider om het zoom-niveau in te stellen.
var slider = new Slider (1, 18, 1); slider.ValueChanged += (sender, e) => { var zoomLevel = e.NewValue; // between 1 and 18 var latlongdegrees = 360 / (Math.Pow(2, zoomLevel)); map.MoveToRegion(new MapSpan (map.VisibleRegion.Center, latlongdegrees, latlongdegrees)); };
of via XAML en code-behind:
<Slider x:Name="SliderZoom" Maximum="18.0" Minimum="1.0" Value="1.0" ValueChanged="OnSliderChanged" />
private void OnSliderChanged(object sender, ValueChangedEventArgs e) { var zoomLevel = e.NewValue; // between 1 and 18 var latlongdegrees = 360 / (Math.Pow(2, zoomLevel)); MyMap.MoveToRegion(new MapSpan(MyMap.VisibleRegion.Center, latlongdegrees, latlongdegrees)); }
Het verplaatsen naar de ingezoomde regio gebeurt via map.MoveToRegion(new MapSpan (map.VisibleRegion.Center, latlongdegrees, latlongdegrees));
.
Maptype instellen
Het gewenste maptype kan u als volgt instellen:
map.MapType = MapType.Street; map.MapType = MapType.Hybrid; map.MapType = MapType.Satellite;
Geocode
U kent de plaats en wilt de coördinaten weten via await geoCoder.GetPositionsForAddressAsync ()
:
Geocoder geoCoder = new Geocoder (); Label l = new Label (); var NinoveAddress = "9400 Ninove, Belgium"; var approximateLocation = await geoCoder.GetPositionsForAddressAsync (NinoveAddress); foreach (var p in approximateLocation) { l.Text += p.Latitude + ", " + p.Longitude + "\n"; }
U kent de coördinaten en wilt de plaats weten via await geoCoder.GetAddressesForPositionAsync ()
:
Geocoder geoCoder = new Geocoder (); Label l = new Label (); var NinovePosition = new Position (50.8210792541504, 3.96598601341248); var possibleAddresses = await geoCoder.GetAddressesForPositionAsync (NinovePosition); foreach (var a in possibleAddresses){ l.Text += a + "\n"; }
Onderstaande code test of een ingevoerde locatie (in de Entry EntryLocation.Text) wel een bestaande plaats bevat. Vervolgens wordt er ingezoomd op deze plaats.
Geocoder geoCoder = new Geocoder (); var item = (await geoCoder.GetPositionsForAddressAsync(EntryLocation.Text)).FirstOrDefault(); if (item == null) { await DisplayAlert("Error", "Unable to decode position", "OK"); return; } var zoomLevel = SliderZoom.Value; // between 1 and 18 var latlongdegrees = 360 / (Math.Pow(2, zoomLevel)); MyMap.MoveToRegion(new MapSpan(item, latlongdegrees, latlongdegrees));
Pinnen toevoegen
var position = new Position(37,-122); // Latitude, Longitude var pin = new Pin { Type = PinType.Place, Position = position, Label = "custom pin", Address = "custom detail info" }; map.Pins.Add(pin);
Opmaak
Het zou me te verleiden om de opmaak van de map en de pinnen in detail te bespreken. Wie meer wil weten kan hier verder lezen.
Mappen – Praktisch voorbeeld
U kunt hier een praktisch voorbeeld downloaden.
- Vergeet niet een key voor Android en/of UWP aan te vragen.
- Op het ogenblik van dit schrijven veroorzaakte
IsShowingUser = true,
een fout, ik heb deze code dan ook moeten verwijderen (of in commentaar plaatsen)
GPS lokalisatie – integreren
Plug-in installeren
- Klik rechts op de Solution om het NuGet package meteen te installeren voor alle projecten.
- Vervolgens klikt u op Manage NuGet packages for Solution….
- Klik op Browse.
- Zoek naar Xam.Plugin.GeoLocator, selecteer alle projecten en de laatste stabiele versie en klik op Install.
Uw app moet toegang krijgen/vragen tot de lokalisatie van het toestel. De gedetailleerde uitleg leest u hier.
UWP
In UWP is dit vrij eenvoudig, u moet de applicatie enkel toegang geven tot de Location.
- Open Properties onder het UWP-project.
- Ga naar Application en klik op Package Manifest….
- Selecteer het tabblad Capabilities en vink Location aan.
Android
Voor Android moeten onderstaande permissies worden toegevoegd aan de reeds ingestelde permissies (vertrekkende vanuit een nieuw project). Deze worden echter automatisch toegevoegd wanneer u het project compileert.
- AccessCoarseLocation
- AccessFineLocation
Deze plug-in bouwt verder op de Permission Plugin, die eveneens, automatisch, toegevoegd is. Deze Permission Plugin vraagt onderstaande aanpassing.
- Voeg onderstaande code toe aan MainActivity.cs dat u eveneens vindt onder het Android-project.
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Android.Content.PM.Permission[] grantResults) { Plugin.Permissions.PermissionsImplementation.Current.OnRequestPermissionsResult(requestCode, permissions, grantResults); }
De volledige code voor MainActivity.cs is:
using Android.App; using Android.Content.PM; using Android.OS; namespace TestGeoLocationPlugin.Droid { [Activity(Label = "TestGeoLocationPlugin", Icon = "@drawable/icon", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)] public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity { protected override void OnCreate(Bundle bundle) { TabLayoutResource = Resource.Layout.Tabbar; ToolbarResource = Resource.Layout.Toolbar; base.OnCreate(bundle); global::Xamarin.Forms.Forms.Init(this, bundle); LoadApplication(new App()); } public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Android.Content.PM.Permission[] grantResults) { Plugin.Permissions.PermissionsImplementation.Current.OnRequestPermissionsResult(requestCode, permissions, grantResults); } } }
iOS
Voor iOS dient u een aantal keys, en bijhorende meldingen die verschijnen wanneer u er gebruik van wilt maken, toevoegen aan het bestandje Info.plist. Dit zijn dezelfde als voor het gebruik van de map (zie hierboven).
- Klik rechts Info.plist dat u vindt onder het iOS-project en kies voor Open with… en selecteer XML (Text) Editor.
- Voeg onderstaande code toe.
<key>NSLocationWhenInUseUsageDescription</key> <string>We are using your location</string> <key>NSLocationAlwaysUsageDescription</key> <string>Can we use your location</string> <key>NSLocationAlwaysAndWhenInUseUsageDescription</key> <string>This app needs access location when open and in the background.</string>
GPS lokalisatie – gebruiken
Onderstaande code-snippets tonen hoe u mappen kan gebruiken.
Begin met de gewenste namespace toe te voegen.
using Plugin.Geolocator;
Uw locatie detecteren
var locator = CrossGeolocator.Current; var position = await locator.GetPositionAsync(TimeSpan.FromSeconds(10)); Debug.WriteLine("Position Status: {0}", position.Timestamp); Debug.WriteLine("Position Latitude: {0}", position.Latitude); Debug.WriteLine("Position Longitude: {0}", position.Longitude);
of uitgebreid als een functie:
public async Task<Position> GetCurrentLocation() { Position position = null; try { var locator = CrossGeolocator.Current; locator.DesiredAccuracy = 100; position = await locator.GetLastKnownLocationAsync(); if (position != null) { //got a cahched position, so let's use it. return; } var available = await locator.GetIsGeolocationAvailableAsync(); var enabled = await locator.GetIsGeolocationEnabled(); if(!available || !enabled) { //not available or enabled return; } position = await locator.GetPositionAsync(TimeSpan.FromSeconds(20), null, true); } catch (Exception ex) { //Display error as we have timed out or can't get location. } if(position == null) return; var output = string.Format("Time: {0} \nLat: {1} \nLong: {2} \nAltitude: {3} \nAltitude Accuracy: {4} \nAccuracy: {5} \nHeading: {6} \nSpeed: {7}", position.Timestamp, position.Latitude, position.Longitude, position.Altitude, position.AltitudeAccuracy, position.Accuracy, position.Heading, position.Speed); Debug.WriteLine(output); }
Gewijzigde positie
Maak hiertoe gebruik van de ingebouwde PositionChanged
-event.
locator.PositionChanged += (sender, e) => { var position = e.Position; latitudeLabel.Text = position.Latitude; longitudeLabel.Text = position.Longitude; };
of uitgebreid.
async Task StartListening() { if(CrossGeolocator.Current.IsListening) return; await CrossGeolocator.Current.StartListeningAsync(TimeSpan.FromSeconds(5), 10, true); CrossGeolocator.Current.PositionChanged += PositionChanged; CrossGeolocator.Current.PositionError += PositionError; } private void PositionChanged(object sender, PositionEventArgs e) { //If updating the UI, ensure you invoke on main thread var position = e.Position; var output = "Full: Lat: " + position.Latitude + " Long: " + position.Longitude; output += "\n" + $"Time: {position.Timestamp}"; output += "\n" + $"Heading: {position.Heading}"; output += "\n" + $"Speed: {position.Speed}"; output += "\n" + $"Accuracy: {position.Accuracy}"; output += "\n" + $"Altitude: {position.Altitude}"; output += "\n" + $"Altitude Accuracy: {position.AltitudeAccuracy}"; Debug.WriteLine(output); } private void PositionError(object sender, PositionErrorEventArgs e) { Debug.WriteLine(e.Error); //Handle event here for errors } async Task StopListening() { if(!CrossGeolocator.Current.IsListening) return; await CrossGeolocator.Current.StopListening(); CrossGeolocator.Current.PositionChanged -= PositionChanged; CrossGeolocator.Current.PositionError -= PositionError; }
Hier vindt u de volledige documentatie.
GPS lokalisatie + mappen – videovoorbeeld
Behandelde Basiscompetenties uit de module ICT Programmeren – Integratie externe functionaliteiten
- IC BC024 – * kan zijn eigen deskundigheid inzake ICT opbouwen
- IC BC232 – kan digitale tools gebruiken om modellen, simulaties en visualisaties van de realiteit te maken
- IC BC254 – kan externe content integreren en structureren
- IC BC258 – houdt rekening met regelgeving m.b.t. licenties voor het gebruik en de publicatie van broncode
- IC BC288 – kan ICT-problemen oplossen