根據 Xamarin.Essentials 官方文件中指出:Xamarin.Essentials 跨平台應用程式開發介面的開發人員提供他們的行動應用程式。透過 Xamarin.Essentials 的套件幫忙,可以將這些功能整合到您的應用程式:加速計 應用程式資訊 電池 剪貼簿 指南針 資料傳輸 裝置顯示資訊 裝置資訊 電子郵件 檔案系統的協助程式 手電筒 地理編碼 地理位置 迴轉儀 磁力計 開啟瀏覽器 電話撥號員 喜好設定 螢幕鎖定 安全儲存體 SMS 文字轉換語音 追蹤版本 震動。
我們現在來體驗關於 Geolocation 地理位置 這項功能,因此,可以參考底下的專案範例,該專案範例
建立測試專案
- 首先,我們先使用 Prism Template Pack 擴充功能所提供的專案樣板,建立起一個 Xamarin.Forms 專案,在這裡我們僅選擇 Android / iOS / UWP 類型的專案;接著,我們需要把 PropertyChanged.Fody NuGet 套件安裝到 .NET Standard 專案類別庫內,並且安裝 FodyWeavers.xml 檔案。
- 緊接著,我們要開始安裝 Xamarin.Essentials NuGet 套件到所有的專案內,在這裡,請使用滑鼠右擊方案節點,選擇 管理方案的 NuGet 套件 選項
- 請在 NuGet - 解決方案 的視窗中,輸入要搜尋的套件名稱 : Xamarin.Essentials並且,請勾選 包括搶鮮版 的文字檢查盒,並且安裝這個套件;我寫這篇文章的時候, Xamarin.Essentials 的最新版本為 0.7.0.17 版本,因此,我們安裝這個版本。
- 當 Xamarin.Essentials 套件安裝完成之後,您將會發現到在 Visual Studio 2017 的錯誤視窗中,出現了底下錯誤訊息
偵測到 Xamarin.Android.Support.Compat 的版本衝突。請直接從專案參考套件,以解決此問題。
XFESFileSystem.Android -> Xamarin.Essentials 0.7.0.17-preview -> Xamarin.Android.Support.CustomTabs 27.0.2 -> Xamarin.Android.Support.Compat (= 27.0.2)
XFESFileSystem.Android -> Xamarin.Android.Support.Design 25.4.0.2 -> Xamarin.Android.Support.Compat (= 25.4.0.2).
- 這個時候您可以參考 Xamarin.Essentials 體驗 1 : File System Helpers 檔案系統存取 文章中的解決辦法完成之後,Android 專案下的 .csproj 檔案,請搜尋這個關鍵字 PackageReference Include="Xamarin.Essentials", 此時,您將會看到底下的內容,安裝了 Xamarin.Android.Support.CustomTabs NuGet 套件,並且都升級到 27.0.2.1 版本當然,最快的方式,就是使用 Visual Studio Code 工具,開啟 Android 專案下的 .csproj 檔案,值些修改成為底下內容,儲存後回到 Visual Studio 2017 下,緊接著重新載入這個 .csproj 檔案,就可以進行 Android 專案的編譯動作囉。
<PackageReference Include="Xamarin.Essentials" Version="0.7.0.17-preview"/>
<PackageReference Include="Xamarin.Android.Support.CustomTabs" Version="27.0.2.1"/>
<PackageReference Include="Xamarin.Android.Support.Design" Version="27.0.2.1" />
<PackageReference Include="Xamarin.Android.Support.v7.AppCompat" Version="27.0.2.1" />
<PackageReference Include="Xamarin.Android.Support.v4" Version="27.0.2.1" />
<PackageReference Include="Xamarin.Android.Support.v7.CardView" Version="27.0.2.1" />
<PackageReference Include="Xamarin.Android.Support.v7.MediaRouter" Version="27.0.2.1" />
- 如此,最初產生的錯誤訊息便會消失了。
- 由於我們要取得裝置中的 GPS 感應器資料,我們需要在每個原生平台設定啟用這樣使用權限首先,請打開 Android 專案內的 MainActivity.cs 檔案在 namespace 前面加入底下宣告
[assembly: UsesPermission(Android.Manifest.Permission.AccessCoarseLocation)]
[assembly: UsesPermission(Android.Manifest.Permission.AccessFineLocation)]
[assembly: UsesFeature("android.hardware.location", Required = false)]
[assembly: UsesFeature("android.hardware.location.gps", Required = false)]
[assembly: UsesFeature("android.hardware.location.network", Required = false)]
在 iOS 專案下,找到 Info.plist 檔案,使用任何文字編輯器打開這個檔案,加入底下宣告
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs access location when open.</string>
在 UWP 專案下,找到 Package.appxmanifest 檔案,使用滑鼠雙擊這個檔案,當 Package.appxmanifest 視窗開啟之後,請切換到 功能 標籤頁次,在 功能 清單中,找到 位置 項目,勾選他
- 我們將開始要進行 View ViewModel Model 的設計了,首先,我們開啟 MainPage.xaml 這個檔案,底下是我們測試的頁面 XAML 語法在這裡,我們將會增加一個 Label 文字控制項,用來顯示抓取到的 GPS 經度 緯度 資訊;另外,有兩個按鈕,一個會開始進行讀取 GPS 經緯度資訊,另外一個是取消抓取經緯度。您可以透過 請選擇取得定位位置精確度 Picker 控制項,來選擇要讀取 GPS 經度 緯度 的精確程度。
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XFESGeolocation.Views.MainPage"
Title="{Binding Title}">
<StackLayout HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand">
<Label Text="Welcome to Xamarin Forms and Prism!" />
<Label Text="{Binding YourLocation}"/>
<Label Text="GeolocationAccuracy"/>
<Picker Title="請選擇取得定位位置精確度"
ItemsSource="{Binding GeolocationAccuracySource}"
ItemDisplayBinding="{Binding Name}"
SelectedItem="{Binding GeolocationAccuracySelected}"/>
<Button Text="取得定位位置" Command="{Binding GetLocationCommand}"/>
<Button Text="取消" Command="{Binding CancelLocationCommand}"
IsVisible="{Binding GetLocation}"/>
</StackLayout>
</ContentPage>
- 請打開 MainPageViewModel.cs 這個檔案在這個練習範例中,我們將會學習到許多開發技巧,這包括了 非同步工作的取消、選擇器 Picker 控制項的應用、取得 GPS 位置、動態的顯示或隱藏控制項。Xamarin.Essentials 套件中的 地理位置 功能,可以使用 Geolocation.GetLocationAsync 這個方法呼叫,若成功執行完畢後,就可以取得 Xamarin.Essentials.Location 類別物件,在這個物件中,透過 Latitude 緯度 / Longtitude 經度 屬性,就可以得知當時裝置所處的 GPS 位置;而我們在呼叫 Geolocation.GetLocationAsync 方法的時候,可以傳入兩個引數:第一個是 GeolocationRequest 用來設定要使用甚麼樣的精確程度來取得 GPS 位置,這個 GeolocationRequest 物件建構的時候,需要提供 GeolocationAccuracy 列舉值,指定 GPS 定位精確度與抓取 GPS 過程的 Timeout 逾期時間;第二個則是 CancellationToken ,這是用來通知非同步工作執行的時候,是否有需要取消此次執行。對於要建構的 GeolocationRequest 類別物件的時候,我們將會由使用者來設定 GPS 定位精確度的設定,透過了 資料綁定 Data Binding 機制,我們在 ViewModel 中,可以由 GeolocationAccuracySelected 物件得知該使用者的設定值。當使用者按下 取得定位位置 的按鈕,我們會建立一 CancellationTokenSource 物件(要這麼做的原因是,一旦這個物件被使用過後,就無法再度使用取消方法呼叫,因此,我們需要在每次執行的時候,都產生一個這個物件;當取得 CancellationTokenSource 物件之後,我們可以從 CancellationTokenSource.Token 屬性取得這個取消動作的權杖,並且傳入到 GeolocationRequest 建構式內。如此,當我們想要取消 Geolocation.GetLocationAsync 方法的時候,就可以呼叫 CancellationTokenSource.Cancel 方法,一旦呼叫這個方法,且非同步工作尚未執行完成,將會觸發這個非同步工作產生一個例外異常,因此,我們需要在這個非同步呼叫方法,使用 try...catch 將其捕捉是否有任何例外異常產生。我們對於第二個按鈕的 IsVisible 屬性,綁定到 ViewModel 中的 GetLocation C# Property 中,因此,若我們想要顯示這個按鈕,只需要在 ViewModel 設定 GetLocation=true;反之,若想要隱藏這個按鈕,我們只需要設定 GetLocation=false。
using Prism.Commands;
using Prism.Mvvm;
using Prism.Navigation;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace XFESGeolocation.ViewModels
{
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Threading;
using Prism.Events;
using Prism.Navigation;
using Prism.Services;
using Xamarin.Essentials;
public class GeolocationAccuracyItem
{
public string Name { get; set; }
public GeolocationAccuracy Item { get; set; }
}
public class MainPageViewModel : INotifyPropertyChanged, INavigationAware
{
public event PropertyChangedEventHandler PropertyChanged;
public string YourLocation { get; set; }
public bool GetLocation { get; set; }
public DelegateCommand GetLocationCommand { get; set; }
public DelegateCommand CancelLocationCommand { get; set; }
private readonly INavigationService _navigationService;
public CancellationTokenSource CTS { get; set; }
public CancellationToken Token { get; set; }
public ObservableCollection<GeolocationAccuracyItem> GeolocationAccuracySource { get; set; } = new ObservableCollection<GeolocationAccuracyItem>();
public GeolocationAccuracyItem GeolocationAccuracySelected { get; set; }
public readonly IPageDialogService _dialogService;
public MainPageViewModel(INavigationService navigationService,
IPageDialogService dialogService)
{
_navigationService = navigationService;
_dialogService = dialogService;
GetLocationCommand = new DelegateCommand(async () =>
{
if(GeolocationAccuracySelected == null)
{
await _dialogService.DisplayAlertAsync("錯誤", "請選擇GPS定位精確度", "確定");
return;
}
CTS = new CancellationTokenSource();
Token = CTS.Token;
GetLocation = true;
try
{
var request = new GeolocationRequest(GeolocationAccuracySelected.Item, TimeSpan.FromSeconds(10));
var location = await Geolocation.GetLocationAsync(request, Token);
if (location != null)
{
YourLocation = $"Latitude 緯度 : {location.Latitude}, Longitude 經度 : {location.Longitude}";
}
}
catch (FeatureNotSupportedException fnsEx)
{
// 處理裝置不支援這項功能的例外異常
}
catch (PermissionException pEx)
{
// 處理關於權限上的例外異常
}
catch (AggregateException ae)
{
// 處理取消的例外異常
}
catch (Exception ex)
{
// 無法取得該GPS位置之例外異常
}
GetLocation = false;
});
CancelLocationCommand = new DelegateCommand(() =>
{
GetLocation = false;
CTS.Cancel();
});
}
public void OnNavigatedFrom(NavigationParameters parameters)
{
}
public void OnNavigatingTo(NavigationParameters parameters)
{
}
public void OnNavigatedTo(NavigationParameters parameters)
{
GeolocationAccuracySource.Clear();
var fooItems = Enum.GetValues(typeof(GeolocationAccuracy));
foreach (GeolocationAccuracy item in fooItems)
{
GeolocationAccuracySource.Add(new GeolocationAccuracyItem()
{
Name = item.ToString(),
Item = item,
});
}
}
}
}
- Android 平台執行結果這是一開始執行的螢幕截圖現在,您可以點選 選擇器 控制器,這個時候,就會跳出可以選擇的 GPS 定位清單。當我們選擇完 GPS 定位精確度之後,便可以按下 取得定位位置 按鈕,此時,您將會看到第二個按鈕顯示在螢幕上了。由於我們使用模擬器進行測試,抓取 GPS 感應器的速度相當的快速,所以,您沒有機會測試使用 取消 按鈕的機會,不過,若您將這個程式在實體手機上執行的時候,就可以體驗這樣的操作了。下圖,是我們抓取到的 GPS 位置結果想要在 Visual Studio for Android Emulator 中來客製化 GPS 定位位置,可以從該模擬器視窗的左邊,看到有一長條工具列。在這個工具列最下方按鈕 >> ,按下去之後,將會顯示出另外一個視窗。在這個視窗中,您可以點選 位置 標籤頁次,使用滑鼠捲動滾輪,便可以縮放地圖,想要把您的 GPS 定位到某個地方,指需要使用滑鼠點選地圖即可。
- 地理位置精確度想要得知不同平台下的地理位置精確度,可以參考 這篇文章