UAP - 使用 Geofencing 地理圍欄
Geofencing, start to finish (XAML) 這是 WP 8.1 時提出的功能,我一直對它感到好奇,因為可應用的層面太廣了,
例如:定點廣告/促銷、觀光區資訊提示、維修人員路程、客戶拜訪通知…等。所以這一篇將來好好了解它。
Geofencing 允許 App 定義 geographical region (地理範圍) 與 App 接收系統通知,讓 設備 進入該範圍或存在附近時可以啟動。
“Geofencing allows an app to define a geographical region and have the system alert the app when the device it's running on enters or exits that area. ”
這正是 Geofencing 的特性與重點。藉由這樣的功能可以在設備進入、範圍內或是離開時結合系統的提醒、推播或是相關功能,
如果正好開啟 App 可以跳出 dialog 的方式讓用戶得知相關的資訊。
要達成上述的目標有幾個步驟要處理:
- 選擇要定義 Geofence 的地點,用來讓 App 知道有那些地理範圍是目的地;
- App 需要註冊與處理:
- 宣告與取得設備的 location 資訊,並且要定時或固定距離更新座標。
- 註冊 event handler,分別在 foreground / background task 的處理是不同的處理方式。
以下便針對這幾個步驟來加以說明,詳細的內容可以參考<Guidelines for geofencing>與<Set up a geofence>。
A. 操作 Geofecing 類別,注冊指定的 geographical region ;
包含所有注冊的 Geofence objects資訊,并且提供狀態事件提供程式可以加以監控并取得指定的 geofence。重點如下:
Type | Name | Description | |||||||||||||||||||||
Event | GeofenceStateChanged | Raised when the state of one or more Geofence objects in the Geofences collection of the GeofenceMonitor has changed. 該事件被觸發來自: 1. 當 App 修改了相關 geofence 物件的設定。 2. 當 App 向 GeofenceMonitor 請求讀取 ReadReports 中的内容。 允許 App 從 suspended 返回時任然可以取得未讀取 queue 中的報告。 相同的在 Background Task 也可以讀取,如果得到的是 SystemCondiction 代表目前設備沒有網路或是不被允許使用座標資訊。 |
|||||||||||||||||||||
StatusChanged | Raised when the status of the GeofenceMonitor has changed. | ||||||||||||||||||||||
Method | ReadReports | Gets a collection of status changes to the Geofence objects in the Geofences collection of the GeofenceMonitor. | |||||||||||||||||||||
Property | Current | Read-only. Gets the GeofenceMonitor object which contains all of an app's Geofence information. | |||||||||||||||||||||
Geofences | Read-only. Returns a vector of the app's Geofence objects currently registered with the system wide GeofenceMonitor. | ||||||||||||||||||||||
LastKnownGeoposition | Read-only. Last reading of the device's location. | ||||||||||||||||||||||
Status | Read-only. Indicates the current state of the GeofenceMonitor.
|
〉Geofence :
作用于定義 geofence 資訊,範圍來協助監控。
Type | Name | Description | ||||||||||||||||||||||||||||||||||
Properties | Duration | Read-only. Gets the time window, beginning after the StartTime, during which the Geofence is monitored. | ||||||||||||||||||||||||||||||||||
DwellTime | Read-only. The minimum time that a position has to be inside or outside of the Geofence in order for the notification to be triggered. | |||||||||||||||||||||||||||||||||||
Geoshape | Read-only. The shape of the geofence region. | |||||||||||||||||||||||||||||||||||
Id | Read-only. The id of the Geofence. | |||||||||||||||||||||||||||||||||||
MonitoredStates | Read-only. Indicates the states that the Geofence is being monitored for. MonitoredGeofenceStates:
|
|||||||||||||||||||||||||||||||||||
SingleUse | Read-only. Indicates whether the Geofence should be triggered once or multiple times. The default value for SingleUse is false. If a geofence is being monitored for both Entered and Exited events and SingleUse is set to true, then the geofence will be removed after the user has both entered and exited the geofence. |
|||||||||||||||||||||||||||||||||||
StartTime | Read-only. The time to start monitoring the Geofence. The default value for this property is a DateTime value of 0, which is the beginning of time, epoch. 當時間通過 StartTime 時啓動監控,當設備進入指定的 geofence 時狀態會變爲 Entered,此時 geofence 會開始計算停留時間(DwellTime),如果滿足了就會觸發事件。 如果 geofence 被啓動時設備在它之外, geofence 不應該被變成 Exited 狀態,設備應該要先進入 geofence 在指定的停留時間再離開才可以完成 Exited 的狀態。 |
|||||||||||||||||||||||||||||||||||
Constructor | Geofence(String,IGeoshape,MonitoredGeofenceStates, Boolean, TimeSpan,DateTime,TimeSpan) |
Initializes a new Geofence object given the id, the shape of the geofence, the states to monitor the geofence for, the singleUse flag, the dwellTime for the geofence, the time to start monitoring the geofence, and the duration of the geofence. IGeoshape: 定義 geographic shape 的界面,主要屬性如下:
|
坐標精準度的比較如下:
- GPS : within approximately 10 meters
- Wi-Fi : between approximately 30 meters and 500 meters
- Cell towers : between approximately 300 meters and 3,000 meters
- IP address : between approximately 1,000 meters and 5,000 meters
更多詳細的説明可以參考《Windows.Devices.Geolocation namespace》,《obtaining the device's current geographic location》,
《tracking the device's location over time》。
B. 如何取得 Device 的座標與更新它;
參考<Detect the user's location>的說明,先在 package.manifest 宣告需要的 capability 接著使用 RequestAccessAsync 向用戶請求開啟定位權限。
1: <Capabilities>
2: <Capability Name="internetClientServer" />
3: <DeviceCapability Name="location" />
4: </Capabilities>
過去在 WP 7 時候也有寫過相關的文件:<Windows Phone - 深入使用Bing Map - 客製Pushpin>、<Windows Phone 7 - 使用Google Map API將地址轉成座標>。
負責連接與存取 current geographic location。重要元素如下:
Type | Name | Description | |||||||||||||||||||||
Event | PositionChanged | Raised when the location is updated. PositionChangedEventArgs 為重要參數,其中 Position 屬性代表座標改變後的值。 |
|||||||||||||||||||||
StatusChanged | Raised when the ability of the Geolocator to provide updated location changes. StatusChangedEventArgs.Status 為重要參數,其列舉值:
|
||||||||||||||||||||||
Method | GetGeopositionAsync | Starts an asynchronous operation to retrieve the current location of the device. 預設是 60 seconds timeout,除非設備有連接電源。 如果請求時系統發現沒有任何 sensor 可以使用,則 7 seconds timeout。 發生 timeout 時會觸發 StatusChanged event,並得到 NoData 狀態,而 PositionChanged event 不會被觸發。 |
|||||||||||||||||||||
GetGeopositionAsync(TimeSpan,TimeSpan) |
Starts an asynchronous operation to retrieve the current location of the device. |
||||||||||||||||||||||
GetGeopositionHistoryAsync(DateTime) |
Starts an asynchronous operation to retrieve the location history of the device.
|
||||||||||||||||||||||
GetGeopositionHistoryAsync(DateTime,TimeSpan) |
Starts an asynchronous operation to retrieve the location history of the device.
|
||||||||||||||||||||||
RequestAccessAsync | Requests permission to access location data. 這是 Win10 才支援的 API,目的在操作用戶的座標資訊前先請求權限與宣告,通常會搭配系統的 URI 讓用戶選擇自動前往設定開始座標功能。例如:「ms-settings://privacy/location」。 |
||||||||||||||||||||||
Property | DesiredAccuracy |
Read/write. The accuracy level at which the Geolocator provides location updates.
需注意有些設備不支援 High 的設定值,它會出現系統不支援的通知。 當 DesiredAccuracyInMeters 或 DesiredAccuracy 屬性被設定時,App 將可以使用到誤差值 500 公尺內的座標資訊(default)。Default:500 公尺,High:10 公尺。 當 App 同時指定了 DesiredAccuracy 與 DesiredAccuracyInMeters, 的話,系統會依照後面設定的為主。 |
|||||||||||||||||||||
DesiredAccuracyInMeters | Read/write. Gets or sets the desired accuracy in meters for data returned from the location service. 提供更多 granularity (粒度)和 更高的位置精準度。 大部分程式只會用到 DesiredAccuracy 屬性即夠用。 |
||||||||||||||||||||||
LocationStatus | Read-only. The status that indicates the ability of the Geolocator to provide location updates. | ||||||||||||||||||||||
MovementThreshold | Read/write. Gets and sets the distance of movement, in meters, relative to the coordinate from the last PositionChanged event, that is required for the Geolocator to raise a PositionChanged event. | ||||||||||||||||||||||
ReportInterval | Read/write. The requested minimum time interval between location updates, in milliseconds. If your application requires updates infrequently, set this value so that location services can conserve power by calculating location only when needed. |
[注意]
- 在 Win10 要使用定位服務前先藉由 RequestAccessAsync 方法在 foreground UI thread 彈出詢問視窗。
- 使用 emulator 要記得更動模擬器中的座標來觸發 PositionChanged event。
使用方法如下:
private Geolocator Locator;
private async void Button_Click(object sender, RoutedEventArgs e)
{
// for win10
// var accessStatus = await Geolocator.RequestAccessAsync();
if (Locator == null)
{
Locator = new Geolocator();
// 設定座標準確度等級,愈高愈耗電
Locator.DesiredAccuracy = PositionAccuracy.Default;
// 設定座標移動多少距離後要觸發 PositionChanged 事件,單位 公尺
Locator.MovementThreshold = 100;
// 設定準確度的誤差值,單位 公尺
Locator.DesiredAccuracyInMeters = 500;
Locator.PositionChanged += locator_PositionChanged;
Locator.StatusChanged += locator_StatusChanged;
}
try
{
var currentLocation = await Locator.GetGeopositionAsync();
if (currentLocation.CivicAddress != null)
{
txtAddress.Text = currentLocation.CivicAddress.ToString();
}
txtLat.Text = currentLocation.Coordinate.Latitude.ToString();
txtLon.Text = currentLocation.Coordinate.Longitude.ToString();
}
catch (UnauthorizedAccessException ex)
{
// 代表沒有開放取得 GPS 座標的權限
}
catch (TimeoutException)
{
// 代表請求取得座標的時間超過了預設的 timeout 值
}
catch (TaskCanceledException) { }
}
void locator_StatusChanged(Geolocator sender, StatusChangedEventArgs args)
{
switch (args.Status)
{
case PositionStatus.Disabled:
break;
case PositionStatus.Initializing:
break;
case PositionStatus.NoData:
// 通知用戶取不到 GPS 座標資訊
break;
case PositionStatus.NotAvailable:
// 通知用戶該設備不支援該功能
break;
case PositionStatus.NotInitialized:
break;
case PositionStatus.Ready:
break;
default:
break;
}
}
void locator_PositionChanged(Geolocator sender, PositionChangedEventArgs args)
{
// 取得最新的座標
var newPosition = args.Position;
}
之前也有寫過相似的文章<Windows Phone 8 - Runtime Location API - 1>與<Windows Phone 8 - Runtime Location API - 2>可以參考看看,例如:
在座標更新時如何請求 cloud service 回應新的附件資料或是更新畫面地圖的位置。
大致瞭解 Geofence 的類別與相關監督的處理元件,以及如何取得設備坐標之後,往下説明如何注冊 Geofence 要處理的狀態與停留時間,
以及 App 如何處理 foreground/background 時對於 GeoMonitorManager 的操作。
1. 準備要建立的 Geofence 資料,以建立 Geocircle爲例;
1: private void CreateGeofence()
2: {
3: GeofenceMonitor.Current.Geofences.Clear();
4:
5: // 設定要監控的狀態
6: MonitoredGeofenceStates state = MonitoredGeofenceStates.Entered |
7: MonitoredGeofenceStates.Exited |
8: MonitoredGeofenceStates.Removed;
9: // 設定是否爲 SingleUse
10: Boolean isSingleUse = false;
11:
12: // 設定 DwellTime, StartTime 與 Duration
13: TimeSpan dwellTime = TimeSpan.FromSeconds(5);
14: DateTimeOffset startTime = DateTime.Now;
15: TimeSpan duration = TimeSpan.FromDays(1);
16:
17: BasicGeoposition pointPosition = new BasicGeoposition
18: {
19: Longitude = 121.5124,
20: Latitude = 25.0457,
21: Altitude = 13
22: };
23: // 建立 Geocircle, 并且 500 m 的範圍
24: Geocircle circle = new Geocircle(pointPosition, 500);
25: Geofence fence2 = new Geofence("fenceId2", circle, state, isSingleUse, dwellTime, startTime, duration);
26: GeofenceMonitor.Current.Geofences.Add(fence2);
27: }
Geofence 提供 4 種類型可以使用,在建立時可以按照需要使用不同的 constructure,并且要加上特定屬性:
- MonitoredStates:那些是你要監控的,加入后會受到指定狀態的通知。
- SingleUse flag:當 Geofence 指定要監控的 MonitoredStates 都被滿足后,自動刪除該 Geofence。
- DwellTime:指定用戶需要在設定的區域内從進入到離開所待住的時間要多久。
- StartTime:何時啓動該 Geofence 的監控。
- Duration:Geofence 持續監控的時間。
2. 請求用戶授權 App 取得定位權限,并于取得坐標后利用 GeofenceMonitor 注冊 Geofence;
1: private async void OpenGeolocator(object sender, RoutedEventArgs e)
2: {
3: // for win10
4: // var accessStatus = await Geolocator.RequestAccessAsync();
5: if (Locator == null)
6: {
7: Locator = new Geolocator();
8: // 設定座標準確度等級,愈高愈耗電
9: Locator.DesiredAccuracy = PositionAccuracy.Default;
10: // 設定座標移動多少距離後要觸發 PositionChanged 事件,單位 公尺
11: Locator.MovementThreshold = 100;
12: // 設定準確度的誤差值,單位 公尺
13: Locator.DesiredAccuracyInMeters = 500;
14: Locator.PositionChanged += locator_PositionChanged;
15: Locator.StatusChanged += locator_StatusChanged;
16: }
17: try
18: {
19: var currentLocation = await Locator.GetGeopositionAsync();
20: // 市政位址
21: if (currentLocation.CivicAddress != null)
22: {
23: txtAddress.Text = currentLocation.CivicAddress.ToString();
24: }
25: txtLat.Text = currentLocation.Coordinate.Latitude.ToString();
26: txtLon.Text = currentLocation.Coordinate.Longitude.ToString();
27: }
28: catch (UnauthorizedAccessException ex)
29: {
30: // 代表沒有開放取得 GPS 座標的權限
31: }
32: catch (TimeoutException)
33: {
34: // 代表請求取得座標的時間超過了預設的 timeout 值
35: }
36: catch (TaskCanceledException) { }
37: }
38:
藉由指定 Geolocator 的坐標精準度與觸發坐標變化事件的距離,注冊 PositionChanged 與 StatusChanged 的事件。
3. 實做在 foreground 監控 GeofenceMointor 提供的事件,監控 Geofence 狀態的改變;
1: void locator_StatusChanged(Geolocator sender, StatusChangedEventArgs args)
2: {
3: switch (args.Status)
4: {
5: case PositionStatus.Disabled:
6: // 用戶不允許存取座標資訊
7: break;
8: case PositionStatus.Initializing:
9: break;
10: case PositionStatus.NoData:
11: // 通知用戶取不到 GPS 座標資訊
12: break;
13: case PositionStatus.NotAvailable:
14: // 通知用戶該設備不支援該功能
15: break;
16: case PositionStatus.NotInitialized:
17: break;
18: case PositionStatus.Ready:
19: // foreground 注冊取得 GeofenceMonitor 的事件
20: var geofences = GeofenceMonitor.Current.Geofences;
21: RegistGenfenceMonitor();
22: break;
23: default:
24: break;
25: }
26: }
27:
28: // 開啓或關閉 GeofenceMonitor 的 GeofenceStateChanged / StatusChanged 事件
29: private void RegistGenfenceMonitor(Boolean isRegist = true)
30: {
31: if (isRegist)
32: {
33: GeofenceMonitor.Current.GeofenceStateChanged += Current_GeofenceStateChanged;
34: GeofenceMonitor.Current.StatusChanged += Current_StatusChanged;
35: }
36: else
37: {
38: GeofenceMonitor.Current.GeofenceStateChanged -= Current_GeofenceStateChanged;
39: GeofenceMonitor.Current.StatusChanged -= Current_StatusChanged;
40: }
41: }
42:
43: //
44: void locator_PositionChanged(Geolocator sender, PositionChangedEventArgs args)
45: {
46: // 隨著設備移動距離符合事件觸發的標準,取得最新的座標,
47: var newPosition = args.Position;
48: }
監控在 Geolocator 狀態是 Ready 的時候開啓 GenfenceMonitor 事件的注冊,包括:GeofenceStateChanged 與 StatusChanged。
其中 GeofenceStateChanged 事件被觸發時,可以檢查是否符合我們預設的目標來提供對應的處理,例如:發出通知。
1: /// <summary>
2: /// 處理 GenfencMonitor 的狀態
3: /// </summary>
4: private void Current_StatusChanged(GeofenceMonitor sender, object args)
5: {
6: switch (sender.Status)
7: {
8: case GeofenceMonitorStatus.Disabled:
9: break;
10: case GeofenceMonitorStatus.Initializing:
11: break;
12: case GeofenceMonitorStatus.NoData:
13: break;
14: case GeofenceMonitorStatus.NotAvailable:
15: break;
16: case GeofenceMonitorStatus.NotInitialized:
17: break;
18: case GeofenceMonitorStatus.Ready:
19: break;
20: }
21: }
22:
23: private void Current_GeofenceStateChanged(GeofenceMonitor sender, object args)
24: {
25: var lastGeoposition = sender.LastKnownGeoposition;
26: var reports = sender.ReadReports();
27: foreach (var item in reports)
28: {
29: if (item.Geofence.Id == "fenceId2")
30: {
31: // 判斷是否爲完成設備進入指定區域并待上指定的時間
32: if (item.NewState == GeofenceState.Entered || item.NewState == GeofenceState.Exited)
33: {
34: // send notification to ui thread
35: NotificationManager.Notify("Geofence Meet", "Device exists in the area.");
36: }
37: else if (item.NewState == GeofenceState.Removed)
38: {
39: // notify remove the Geofence
40: NotificationManager.Notify("Geofence remove", "Geofence be removed.");
41: }
42: break;
43: }
44: }
45: }
上述是在 foreground 處理 Geolocator 與 GeofenceMonitor 的任務,最重要就是注冊自己預期檢測的 Geofence 與 處理 GeofenceMonitor
的 GeofenceStatusChanged 事件,才能符合完成任務。更多的詳細内容可以參考<Handle geofence notifications in the foreground (XAML)>。
4. 實作 Background Task 搭配取得坐標資訊與搭配 GeofenceMonitor 觸發事件發出消息;
4-1. 建立一個 Background Task 專門處理 GeolocationMonitor 中已經保存的 Geofence 狀態的改變資訊。
1:
2: public sealed class GeofenceBackgroundTask : IBackgroundTask
3: {
4: CancellationTokenSource cts = null;
5:
6: public GeofenceBackgroundTask()
7: {
8: }
9:
10: async void IBackgroundTask.Run(IBackgroundTaskInstance taskInstance)
11: {
12: BackgroundTaskDeferral deferral = taskInstance.GetDeferral();
13:
14: try
15: {
16: // Associate a cancellation handler with the background task.
17: taskInstance.Canceled += new BackgroundTaskCanceledEventHandler(OnCanceled);
18:
19: // Get cancellation token
20: if (cts == null)
21: {
22: cts = new CancellationTokenSource();
23: }
24: CancellationToken token = cts.Token;
25:
26: // Create geolocator object
27: Geolocator geolocator = new Geolocator();
28:
29: // Make the request for the current position
30: Geoposition pos = await geolocator.GetGeopositionAsync().AsTask(token);
31:
32: GetGeofenceStateChangedReports(pos);
33: }
34: catch (UnauthorizedAccessException)
35: {
36: WipeGeofenceDataFromData("Status",
37: "Location Permissions disabled by user. " +
38: "Enable access through the settings charm to enable the background task.");
39: WipeGeofenceDataFromData("GeofenceEvent", "");
40: }
41: finally
42: {
43: cts = null;
44:
45: deferral.Complete();
46: }
47: }
48:
49: private void WipeGeofenceDataFromData(String key, String value)
50: {
51: var settings = ApplicationData.Current.LocalSettings;
52: settings.Values[key] = value;
53: }
54:
55: private void OnCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
56: {
57: if (cts != null)
58: {
59: cts.Cancel();
60: cts = null;
61: }
62: }
63:
64: private void GetGeofenceStateChangedReports(Geoposition pos)
65: {
66: GeofenceMonitor monitor = GeofenceMonitor.Current;
67: Geoposition posLastKnown = monitor.LastKnownGeoposition;
68: bool eventOfInterest = true;
69:
70: if (true == eventOfInterest)
71: {
72: if (true == eventOfInterest)
73: {
74: string geofenceItemEvent = null;
75:
76: int numEventsOfInterest = 0;
77:
78: // Retrieve a vector of state change reports
79: var reports = GeofenceMonitor.Current.ReadReports();
80:
81: foreach (GeofenceStateChangeReport report in reports)
82: {
83: GeofenceState state = report.NewState;
84:
85: geofenceItemEvent = report.Geofence.Id + " ";
86:
87: if (state == GeofenceState.Removed)
88: {
89: GeofenceRemovalReason reason = report.RemovalReason;
90:
91: if (reason == GeofenceRemovalReason.Expired)
92: {
93: geofenceItemEvent += " (Removed/Expired)";
94: }
95: else if (reason == GeofenceRemovalReason.Used)
96: {
97: geofenceItemEvent += " (Removed/Used)";
98: }
99: }
100: else if (state == GeofenceState.Entered)
101: {
102: geofenceItemEvent += " (Entered)";
103: }
104: else if (state == GeofenceState.Exited)
105: {
106: geofenceItemEvent += " (Exited)";
107: }
108:
109: ++numEventsOfInterest;
110: }
111:
112: if (true == eventOfInterest && 0 != numEventsOfInterest)
113: {
114: // NOTE: Other notification mechanisms can be used here, such as Badge and/or Tile updates.
115: DoToast(numEventsOfInterest, geofenceItemEvent);
116: }
117: }
118: }
119: }
120:
121: /// <summary>
122: /// Helper method to pop a toast
123: /// </summary>
124: private void DoToast(int numEventsOfInterest, string eventName)
125: {
126: // pop a toast for each geofence event
127: ToastNotifier ToastNotifier = ToastNotificationManager.CreateToastNotifier();
128:
129: // Create a two line toast and add audio reminder
130:
131: // Here the xml that will be passed to the
132: // ToastNotification for the toast is retrieved
133: Windows.Data.Xml.Dom.XmlDocument toastXml = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText02);
134:
135: // Set both lines of text
136: Windows.Data.Xml.Dom.XmlNodeList toastNodeList = toastXml.GetElementsByTagName("text");
137: toastNodeList.Item(0).AppendChild(toastXml.CreateTextNode("Geolocation Sample"));
138:
139: if (1 == numEventsOfInterest)
140: {
141: toastNodeList.Item(1).AppendChild(toastXml.CreateTextNode(eventName));
142: }
143: else
144: {
145: string secondLine = "There are " + numEventsOfInterest + " new geofence events";
146: toastNodeList.Item(1).AppendChild(toastXml.CreateTextNode(secondLine));
147: }
148:
149: // now create a xml node for the audio source
150: Windows.Data.Xml.Dom.IXmlNode toastNode = toastXml.SelectSingleNode("/toast");
151: Windows.Data.Xml.Dom.XmlElement audio = toastXml.CreateElement("audio");
152: audio.SetAttribute("src", "ms-winsoundevent:Notification.SMS");
153:
154: ToastNotification toast = new ToastNotification(toastXml);
155: ToastNotifier.Show(toast);
156: }
157: }
這些資訊可以協助處理判斷有哪些 Geofence 已經完成了指定監控的 state。
4-2. 將建立好的 Background Task 在 App 裏面加以注冊。
1: <Extensions>
2: <Extension Category="windows.backgroundTasks" EntryPoint="BackgroundTaskLocation.GeofenceBackgroundTask">
3: <BackgroundTasks>
4: <m2:Task Type="location" />
5: </BackgroundTasks>
6: </Extension>
7: </Extensions>
將建立好的 Background Task 加入 Package.appxmanifest 檔案。
1: private const string SampleBackgroundTaskName = "GeofenceBackgroundTask";
2: private const string SampleBackgroundTaskEntryPoint = "BackgroundTaskLocation.GeofenceBackgroundTask";
3: private IBackgroundTaskRegistration geofenceTask = null;
4:
5: private async void OnRegistBackgroundTaskLocation(object sender, RoutedEventArgs e)
6: {
7: // 請求取得 Background Task 的權限。
8: // 如果用戶已經同意過依然無法取得權限的話,需要的 設定中的定位 權限檢查是否有手動關閉對於這個 App 的權限
9: BackgroundAccessStatus backgroundAccessStatus = await BackgroundExecutionManager.RequestAccessAsync();
10:
11: // 建立一個新的 background task
12: BackgroundTaskBuilder geofenceTaskBuilder = new BackgroundTaskBuilder();
13: geofenceTaskBuilder.Name = SampleBackgroundTaskName;
14: geofenceTaskBuilder.TaskEntryPoint = SampleBackgroundTaskEntryPoint;
15:
16: // 建立一個新的 location trigger
17: var trigger = new LocationTrigger(LocationTriggerType.Geofence);
18:
19: // 將 location trigger 與 background task 建立起關聯
20: geofenceTaskBuilder.SetTrigger(trigger);
21:
22: // 如果 background task 在 oncompleted 時需要 user presence 與 internet connection, 則需要加入以下宣告
23: // SystemCondition condition = new SystemCondition(SystemConditionType.UserPresent | SystemConditionType.InternetAvailable);
24: // geofenceTaskBuilder.AddCondition(condition);
25:
26: // 注冊 background task
27: geofenceTask = geofenceTaskBuilder.Register();
28:
29: // 建立 new background task 的 completed event handler
30: geofenceTask.Completed += new BackgroundTaskCompletedEventHandler(OnCompleted);
31:
32: switch (backgroundAccessStatus)
33: {
34: case BackgroundAccessStatus.Unspecified:
35: case BackgroundAccessStatus.Denied:
36: NotificationManager.Notify("Not able to run in background.", "");
37: break;
38:
39: default:
40: // Ensure we have presented the location consent prompt (by asynchronously getting the current
41: // position). This must be done here because the background task cannot display UI.
42: OnGetGeopositionAsync(sender, e);
43: break;
44: }
45: }
46:
47: async private void OnCompleted(IBackgroundTaskRegistration sender, BackgroundTaskCompletedEventArgs e)
48: {
49: if (sender != null)
50: {
51: // Update the UI with progress reported by the background task
52: await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
53: {
54: try
55: {
56: // If the background task threw an exception, display the exception in
57: // the error text box.
58: e.CheckResult();
59:
60: // Update the UI with the completion status of the background task
61: // The Run method of the background task sets the LocalSettings.
62: var settings = ApplicationData.Current.LocalSettings;
63: }
64: catch (Exception)
65: {
66: // The background task had an error
67: }
68: });
69: }
70: }
以上加入注冊 Background Task 到背景原件裏面,藉由 BackgroundExecutionManager.RequestAccessAsync(); 取得用戶的權限,
相關測試的方式可以參考<Test and debug your geofencing apps>。
[範例程式]
======
以上分享如何注冊 Geofence 與 GeofenceMonitor 搭配 Geolocator 來識別設備是否符合監控的 geofence。
感覺這個很多的題目可以實現,希望簡單的介紹對大家有所幫助,謝謝。
References:
〉Geofencing, start to finish (XAML)
〉Detect the user's location & geolocation sample
〉Guidelines for geofencing / Guidelines for using sensitive devices / Set up a geofence
〉Handle geofence notifications in the foreground
〉Listen for geofence events in the background
〉Handle geofence notifications from a background task
〉Test and debug your geofencing apps
〉Creating a Location-Aware App with Geofencing
〉Guidelines for location-aware apps / Display your location using Bing Maps
〉Windows 10 Insider Preview geolocation sample / Windows 8.1 geolocation sample
〉Building Cross-Platform iBeacon Apps for iOS, Android and Windows with C# and Xamarin
〉Windows 8.1 Preview: Geo-Fencing TriggersSupporting your app with background tasks (XAML)
〉Geolocation sample & Windows-universal-samples / Samples / Geolocation / (UWP)
〉Listen for geofence events in the background
〉Respond to location updates (XAML)
〉Handle geofence notifications from a background task (XAML)
〉GeofenceMonitor.StatusChanged